fix color
This commit is contained in:
parent
6b6605a2b0
commit
5088e3ad1c
20 changed files with 623 additions and 423 deletions
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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("""
|
||||
<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
<gradient:#87CEEB:#4169E1><bold>🛠️ Управление кастомными командами</bold></gradient>
|
||||
|
||||
<#FFEB3B>📋 Доступные команды:</color>
|
||||
<#9E9E9E>• <#FFFFFF>/customcommands list</color> - список команд
|
||||
<#9E9E9E>• <#FFFFFF>/customcommands reload</color> - перезагрузить команды
|
||||
<#9E9E9E>• <#FFFFFF>/customcommands enable <команда></color> - включить команду
|
||||
<#9E9E9E>• <#FFFFFF>/customcommands disable <команда></color> - выключить команду
|
||||
|
||||
<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
""");
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
|
||||
private void showCommandsList(CommandSender sender) {
|
||||
net.kyori.adventure.text.TextComponent.Builder message = Component.text()
|
||||
.append(ChatFormatter.parse("<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>\n"))
|
||||
.append(ChatFormatter.parse("<gradient:#87CEEB:#4169E1><bold>📋 Кастомные команды</bold></gradient>\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() + "</color> " + status + permission + "\n"
|
||||
));
|
||||
}
|
||||
|
||||
message.append(ChatFormatter.parse("\n<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>"));
|
||||
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<String> 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<>();
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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</color> <#808080>- Перезагрузить конфиги"));
|
||||
sender.sendMessage(MM.deserialize("<#FFFF00>/lochat commands</color> <#808080>- Список кастомных команд"));
|
||||
sender.sendMessage(MM.deserialize("<#FFFF00>/lochat commands reload</color> <#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() + "</color> <#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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}] ");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, CustomCommandData> getCommands() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
public record CustomCommandData(String name, String permission, String message, List<String> aliases, String type,
|
||||
String target) {
|
||||
String target, boolean enabled) {
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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" ]
|
||||
|
|
|
|||
|
|
@ -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: |
|
||||
<gradient:#FFD700:#FFA500>═══════ Помощь по серверу ═══════</gradient>
|
||||
<gradient:#87CEEB:#4682B4>/rules</gradient> <gray>- правила сервера</gray>
|
||||
<gradient:#87CEEB:#4682B4>/discord</gradient> <gray>- наш Discord</gray>
|
||||
<gradient:#87CEEB:#4682B4>/website</gradient> <gray>- официальный сайт</gray>
|
||||
<gradient:#87CEEB:#4682B4>/coords</gradient> <gray>- ваши координаты</gray>
|
||||
<gradient:#87CEEB:#4682B4>/time</gradient> <gray>- время на сервере</gray>
|
||||
aliases: [ "помощь", "хелп" ]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
rules:
|
||||
message: |
|
||||
<gradient:#FF6B6B:#FF4757>═══════ Правила сервера ═══════</gradient>
|
||||
<white>1.</white> <gray>Не используйте читы и моды</gray>
|
||||
<white>2.</white> <gray>Уважайте других игроков</gray>
|
||||
<white>3.</white> <gray>Не спамьте в чате</gray>
|
||||
<white>4.</white> <gray>Не стройте рядом с чужими постройками</gray>
|
||||
<white>5.</white> <gray>Не используйте мат и оскорбления</gray>
|
||||
|
||||
<gradient:#FFA726:#FF9800>Нарушение правил карается мутом или баном!</gradient>
|
||||
aliases: [ "правила", "rule" ]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
discord:
|
||||
message: |
|
||||
<gradient:#7289DA:#5865F2>═══════ Наш Discord ═══════</gradient>
|
||||
<gray>Присоединяйтесь к нашему сообществу!</gray>
|
||||
|
||||
<click:open_url:'https://discord.gg/example'><gradient:#87CEEB:#4682B4>🔗 discord.gg/example</gradient></click>
|
||||
|
||||
<gray>В Discord вы можете:</gray>
|
||||
<white>•</white> <gray>Общаться с игроками</gray>
|
||||
<white>•</white> <gray>Получать новости сервера</gray>
|
||||
<white>•</white> <gray>Участвовать в событиях</gray>
|
||||
aliases: [ "дискорд", "ds" ]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
website:
|
||||
message: |
|
||||
<gradient:#00FF88:#00CC66>═══════ Официальный сайт ═══════</gradient>
|
||||
<click:open_url:'https://example.com'><gradient:#87CEEB:#4682B4>🌐 example.com</gradient></click>
|
||||
|
||||
<gray>На сайте доступно:</gray>
|
||||
<white>•</white> <gray>Карта сервера</gray>
|
||||
<white>•</white> <gray>Статистика игроков</gray>
|
||||
<white>•</white> <gray>Форум и новости</gray>
|
||||
aliases: [ "сайт", "site" ]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# УТИЛИТЫ
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
coords:
|
||||
message: |
|
||||
<gradient:#FFA726:#FF9800>Ваши координаты:</gradient>
|
||||
<gradient:#87CEEB:#4682B4>X:</gradient> <white>{x}</white>
|
||||
<gradient:#87CEEB:#4682B4>Y:</gradient> <white>{y}</white>
|
||||
<gradient:#87CEEB:#4682B4>Z:</gradient> <white>{z}</white>
|
||||
<gradient:#87CEEB:#4682B4>Мир:</gradient> <white>{world}</white>
|
||||
aliases: [ "координаты", "pos", "position" ]
|
||||
type: "actionbar"
|
||||
target: "sender"
|
||||
|
||||
time:
|
||||
message: |
|
||||
<gradient:#87CEEB:#4682B4>Время на сервере:</gradient> <white>%server_time_24%</white>
|
||||
<gradient:#87CEEB:#4682B4>Дата:</gradient> <white>%server_date%</white>
|
||||
<gradient:#87CEEB:#4682B4>Онлайн:</gradient> <white>%server_online%</white> <gray>игроков</gray>
|
||||
aliases: [ "время", "дата" ]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# АДМИНСКИЕ КОМАНДЫ
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
restart-warning:
|
||||
permission: "lochat.admin"
|
||||
message: |
|
||||
<gradient:#FF6B6B:#FF4757>⚠ ВНИМАНИЕ! ⚠</gradient>
|
||||
<gradient:#FFA726:#FF9800>Сервер будет перезагружен через 5 минут!</gradient>
|
||||
<gray>Сохраните свой прогресс и подготовьтесь к перезагрузке.</gray>
|
||||
aliases: [ "рестарт", "reboot" ]
|
||||
type: "title"
|
||||
target: "all"
|
||||
|
||||
maintenance:
|
||||
permission: "lochat.admin"
|
||||
message: |
|
||||
<gradient:#FF6B6B:#FF4757>Сервер переходит в режим технических работ</gradient>
|
||||
<gray>Ожидаемое время: 30 минут</gray>
|
||||
aliases: [ "тех-работы", "maintenance" ]
|
||||
type: "broadcast"
|
||||
target: "all"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# VIP КОМАНДЫ
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
vip-info:
|
||||
permission: "lochat.vip"
|
||||
message: |
|
||||
<gradient:#FFD700:#FFA500>═══════ VIP Привилегии ═══════</gradient>
|
||||
<white>•</white> <gray>Цветной ник и префикс</gray>
|
||||
<white>•</white> <gray>Приоритет входа на сервер</gray>
|
||||
<white>•</white> <gray>Дополнительные команды</gray>
|
||||
<white>•</white> <gray>Больше возможностей в чате</gray>
|
||||
|
||||
<gradient:#6BCB77:#4ECDC4>Спасибо за поддержку сервера!</gradient>
|
||||
type: "chat"
|
||||
target: "permission:lochat.vip"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# РАЗВЛЕКАТЕЛЬНЫЕ КОМАНДЫ
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
welcome:
|
||||
message: |
|
||||
<gradient:#FFD700:#FFA500>Добро пожаловать на сервер!</gradient>
|
||||
<gradient:#87CEEB:#4682B4>Игрок {player} присоединился к игре</gradient>
|
||||
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% - текущая дата
|
||||
# И многие другие...
|
||||
|
|
@ -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
|
||||
|
|
|
|||
140
src/main/resources/custom-commands.yml
Normal file
140
src/main/resources/custom-commands.yml
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
# ╔══════════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ Custom Commands Configuration ║
|
||||
# ║ Конфигурация кастомных команд ║
|
||||
# ╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
|
||||
# Информационные команды
|
||||
help:
|
||||
enabled: true
|
||||
message: |
|
||||
<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
<gradient:#87CEEB:#4169E1><bold>📚 Помощь по серверу</bold></gradient>
|
||||
|
||||
<#FFEB3B>🏠 Основные команды:</color>
|
||||
<#9E9E9E>• <#FFFFFF>/spawn</color> - телепорт на спавн
|
||||
<#9E9E9E>• <#FFFFFF>/home</color> - телепорт домой
|
||||
<#9E9E9E>• <#FFFFFF>/sethome</color> - установить дом
|
||||
|
||||
<#FFEB3B>💬 Чат команды:</color>
|
||||
<#9E9E9E>• <#FFFFFF>!сообщение</color> - глобальный чат
|
||||
<#9E9E9E>• <#FFFFFF>/msg игрок</color> - личное сообщение
|
||||
<#9E9E9E>• <#FFFFFF>/reply</color> - ответить на ЛС
|
||||
|
||||
<#FFEB3B>🎨 Кастомизация:</color>
|
||||
<#9E9E9E>• <#FFFFFF>/color</color> - градиентный ник
|
||||
<#9E9E9E>• <#FFFFFF>/prefix</color> - кастомный префикс
|
||||
|
||||
<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
aliases: ["помощь", "хелп"]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
rules:
|
||||
enabled: true
|
||||
message: |
|
||||
<gradient:#FF6B6B:#FF4500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
<gradient:#87CEEB:#4169E1><bold>📋 Правила сервера</bold></gradient>
|
||||
|
||||
<#F44336><bold>🚫 Запрещено:</bold></color>
|
||||
<#9E9E9E>• Читерство и использование модов
|
||||
<#9E9E9E>• Гриферство и воровство
|
||||
<#9E9E9E>• Мат и оскорбления
|
||||
<#9E9E9E>• Спам в чате
|
||||
<#9E9E9E>• Реклама других серверов
|
||||
|
||||
<#4CAF50><bold>✅ Разрешено:</bold></color>
|
||||
<#9E9E9E>• Строительство в любом стиле
|
||||
<#9E9E9E>• Торговля между игроками
|
||||
<#9E9E9E>• Создание команд и кланов
|
||||
<#9E9E9E>• Использование /home и /spawn
|
||||
|
||||
<#FFA726><bold>⚠️ За нарушения:</bold></color>
|
||||
<#9E9E9E>• Предупреждение → Мут → Бан
|
||||
|
||||
<gradient:#FF6B6B:#FF4500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
aliases: ["правила", "rule"]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
discord:
|
||||
enabled: true
|
||||
message: |
|
||||
<gradient:#5865F2:#7289DA><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
<gradient:#87CEEB:#4169E1><bold>💬 Discord сервер</bold></gradient>
|
||||
|
||||
<#5865F2><bold>Присоединяйся к нашему Discord!</bold></color>
|
||||
|
||||
<#FFEB3B>🔗 Ссылка:</color> <click:open_url:'https://discord.gg/yourserver'><u><#00BFFF>discord.gg/yourserver</u></click>
|
||||
|
||||
<#FFEB3B>📢 В Discord ты найдешь:</color>
|
||||
<#9E9E9E>• Общение с игроками
|
||||
<#9E9E9E>• Новости и обновления
|
||||
<#9E9E9E>• Поддержку администрации
|
||||
<#9E9E9E>• Конкурсы и ивенты
|
||||
|
||||
<gradient:#5865F2:#7289DA><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
aliases: ["дискорд", "ds"]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
coords:
|
||||
enabled: true
|
||||
message: "<#FFEB3B>📍 <bold>Ваши координаты:</bold></color> <#9E9E9E>X: <#FFFFFF>{x}</color> Y: <#FFFFFF>{y}</color> Z: <#FFFFFF>{z}</color> <#9E9E9E>Мир: <#4CAF50>{world}</color>"
|
||||
aliases: ["координаты", "pos", "position"]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
ping:
|
||||
enabled: true
|
||||
message: "<#FFEB3B>📶 <bold>Ваш пинг:</bold></color> <#4CAF50>{ping}ms</color>"
|
||||
aliases: ["пинг"]
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
type: "chat"
|
||||
target: "sender"
|
||||
|
||||
hub:
|
||||
enabled: true
|
||||
message: "<#4CAF50>🏠 Подключение к хабу...</color>"
|
||||
aliases: ["lobby", "хаб"]
|
||||
type: "bungee"
|
||||
target: "sender"
|
||||
server: "hub"
|
||||
|
||||
discord:
|
||||
enabled: true
|
||||
message: |
|
||||
<gradient:#5865F2:#7289DA><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
<gradient:#87CEEB:#4169E1><bold>💬 Discord сервер</bold></gradient>
|
||||
|
||||
<#5865F2><bold>Присоединяйся к нашему Discord!</bold></color>
|
||||
|
||||
<#FFEB3B>🔗 Ссылка:</color> <click:open_url:'https://discord.gg/yourserver'><u><#00BFFF>discord.gg/yourserver</u></click>
|
||||
|
||||
<#FFEB3B>📢 В Discord ты найдешь:</color>
|
||||
<#9E9E9E>• Общение с игроками
|
||||
<#9E9E9E>• Новости и обновления
|
||||
<#9E9E9E>• Поддержку администрации
|
||||
<#9E9E9E>• Конкурсы и ивенты
|
||||
|
||||
<gradient:#5865F2:#7289DA><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>
|
||||
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><bold>🔧 Сервер переведен в режим технических работ</bold></color>"
|
||||
aliases: ["тех-работы", "техработы"]
|
||||
type: "title"
|
||||
target: "all"
|
||||
|
|
@ -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текст, <gradient:&#FF0000:�FF00>текст</gradient>"
|
||||
taken: "&#FF6B6BЭтот ник уже занят!"
|
||||
error: "&#FF6B6BНе удалось установить ник!"
|
||||
|
|
|
|||
|
|
@ -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 <action>
|
||||
permission: chat.me
|
||||
aliases: [ action, действие ]
|
||||
|
||||
broadcast:
|
||||
description: Broadcast message to all players
|
||||
usage: /broadcast <message>
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue