fix color

This commit is contained in:
loki5512344 2026-03-13 15:51:47 +01:00
parent 6b6605a2b0
commit 5088e3ad1c
20 changed files with 623 additions and 423 deletions

View file

@ -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() {

View file

@ -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<>();
}
}

View file

@ -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());
}
});
}

View file

@ -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("&#808080Команды:"));
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("&#00FF00Конфигурация перезагружена!"));
sender.sendMessage(MM.deserialize("<#00FF00>Конфигурация перезагружена!"));
}
case "commands" -> {
if (args.length > 1 && args[1].equalsIgnoreCase("reload")) {
plugin.getCustomCommandManager().reload();
sender.sendMessage(MM.deserialize("&#00FF00Кастомные команды перезагружены!"));
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() + " &#808080(" + cmd.type() + ")"));
sender.sendMessage(MM.deserialize("<#FFEB3B>/" + cmd.name() + "</color> <#808080>(" + cmd.type() + ")"));
if (!cmd.aliases().isEmpty()) {
sender.sendMessage(MM.deserialize("&#808080 Алиасы: " + 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;

View file

@ -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

View file

@ -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}] ");
}

View file

@ -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);
});
});
}

View file

@ -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();

View file

@ -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()) {

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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) {
}
}

View file

@ -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);
}

View file

@ -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" ]

View file

@ -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% - текущая дата
# И многие другие...

View file

@ -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

View 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"

View file

@ -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: "&#6BCB77Префикс установлен!"
prefix-reset: "&#FFA726Префикс сброшен"
prefix-reset-success: "&#6BCB77Префикс успешно сброшен!"
prefix-enabled: "&#6BCB77Префикс включен"
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: "&#6BCB77Г&#62C973р&#5AC76Fа&#51C56Bд&#49C367и&#40C163е&#38BF5Fн&#2FBD5Bт &#27BB57у&#1EB953с&#16B74Fп&#0DB54Bе&#05B347ш&#05B347н&#05B347о &#05B347у&#05B347с&#05B347т&#05B347а&#05B347н&#05B347о&#05B347в&#05B347л&#05B347е&#05B347н&#05B347!"
color-no-colors: "&#FFA726У вас нет установленных цветов!"
color-copy-usage: "&#FFA726Использование: /color copy <игрок>"
color-copy-no-colors: "&#FFA726У игрока {player} нет установленных цветов!"
prefix-help: "&#FFD700Использование: /prefix <текст> или /prefix reset"
prefix-success: "&#6BCB77Префикс успешно установлен! Стоимость: {price} поинтов"
prefix-success-free: "&#6BCB77Префикс успешно установлен!"
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: "&#6BCB77Конфигурация градиента перезагружена!"
info-header: "&#FFD700=== Информация о {player} ==="
info-prefix: "&#87CEEBПрефикс: &#FFFFFF{prefix}"
info-prefix-enabled: "&#87CEEBПрефикс включен: &#FFFFFF{enabled}"
info-colors: "&#87CEEBЦвета: &#FFFFFF{colors}"
info-color-enabled: "&#87CEEBЦвет включен: &#FFFFFF{enabled}"
info-prefix-purchased: "&#87CEEBПрефикс куплен: &#FFFFFF{purchased}"
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ КАСТОМНЫЕ НИКИ │
# └─────────────────────────────────────────────────────────────────────────────┘
nick:
current: "&#87CEEBВаш текущий ник: {nick}"
usage: "&#FFA726Использование: /nick <ник> или /nick reset"
reset-usage: "&#FFA726Используйте /nick reset для сброса"
set-usage: "&#FFA726Используйте /nick <ник> для установки"
no-nick: "&#FFA726У вас нет кастомного ника"
reset-success: "&#6BCB77Ваш ник сброшен!"
set-success: "&#6BCB77Ваш ник изменён на: {nick}"
invalid: "&#FF6B6BНевалидный ник!"
requirements-header: "&#FFA726Требования:"
requirements-length: "&#87CEEB• Длина: 3-16 символов"
requirements-chars: "&#87CEEB• Разрешены: буквы, цифры, _, русские буквы"
requirements-colors: "&#87CEEB• Поддержка цветов: &#FF0000текст, <gradient:&#FF0000:&#00FF00>текст</gradient>"
taken: "&#FF6B6BЭтот ник уже занят!"
error: "&#FF6B6BНе удалось установить ник!"

View file

@ -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