This commit is contained in:
loki5512344 2026-03-11 14:35:00 +01:00
parent 5ece2192a2
commit 6b6605a2b0
6 changed files with 212 additions and 160 deletions

View file

@ -1,6 +1,5 @@
plugins {
java
checkstyle
}
group = "com.loki"
@ -53,17 +52,3 @@ tasks.jar {
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
checkstyle {
toolVersion = "10.12.5"
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
isIgnoreFailures = true
maxWarnings = 999
}
tasks.withType<Checkstyle> {
reports {
xml.required.set(false)
html.required.set(true)
}
}

View file

@ -28,7 +28,6 @@ public class CustomCommandManager {
// Информационные команды
commands.put("help", new HelpCommand(plugin));
commands.put("rules", new RulesCommand(plugin));
commands.put("discord", new DiscordCommand(plugin));
// Утилиты
commands.put("coords", new CoordsCommand(plugin));

View file

@ -8,6 +8,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
@ -141,7 +142,7 @@ public class DiscordWebhook {
* Синхронная отправка в вебхук
*/
private boolean sendWebhookSync(String jsonPayload) throws IOException {
URL url = new URL(webhookUrl);
URL url = URI.create(webhookUrl).toURL();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {

View file

@ -72,8 +72,8 @@ public class DiscordEventListener implements Listener {
if (!discord.isEnabled()) return;
Player player = event.getEntity();
String deathMessage = event.getDeathMessage() != null ?
PlainTextComponentSerializer.plainText().serialize(event.getDeathMessage()) :
String deathMessage = event.deathMessage() != null ?
PlainTextComponentSerializer.plainText().serialize(event.deathMessage()) :
"умер";
discord.sendPlayerDeath(player, deathMessage);

View file

@ -33,20 +33,25 @@ public class EnhancedChatRenderer implements ChatRenderer {
@Override
public Component render(Player source, Component sourceDisplayName, Component message, Audience viewer) {
// Префикс в зависимости от типа чата
// Красивые префиксы с градиентами и эмодзи
Component prefixComponent;
if (isGlobal) {
// [G] с желтой буквой G
prefixComponent = Component.text("[")
.color(net.kyori.adventure.text.format.NamedTextColor.GRAY)
.append(Component.text("G").color(net.kyori.adventure.text.format.NamedTextColor.GOLD))
.append(Component.text("]").color(net.kyori.adventure.text.format.NamedTextColor.GRAY));
// 🌍 GLOBAL с градиентом от золотого к оранжевому
prefixComponent = Component.text("🌍 ")
.append(Component.text("G").color(net.kyori.adventure.text.format.TextColor.fromHexString("#FFD700")))
.append(Component.text("L").color(net.kyori.adventure.text.format.TextColor.fromHexString("#FFA500")))
.append(Component.text("O").color(net.kyori.adventure.text.format.TextColor.fromHexString("#FF8C00")))
.append(Component.text("B").color(net.kyori.adventure.text.format.TextColor.fromHexString("#FF7F50")))
.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 {
// [L] с голубой буквой L
prefixComponent = Component.text("[")
.color(net.kyori.adventure.text.format.NamedTextColor.GRAY)
.append(Component.text("L").color(net.kyori.adventure.text.format.NamedTextColor.AQUA))
.append(Component.text("]").color(net.kyori.adventure.text.format.NamedTextColor.GRAY));
// 📍 LOCAL с градиентом от голубого к синему
prefixComponent = Component.text("📍 ")
.append(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);
@ -60,10 +65,15 @@ public class EnhancedChatRenderer implements ChatRenderer {
processedMessage = mentionHandler.processMentions(processedMessage, source, viewerPlayer);
}
// Красивое разделение с градиентными стрелками
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"));
return prefixComponent
.append(Component.text(" "))
.append(separator)
.append(playerComponent)
.append(Component.text(": ").color(net.kyori.adventure.text.format.NamedTextColor.GRAY))
.append(Component.text(": ").color(net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY))
.append(processedMessage);
}
@ -75,10 +85,16 @@ public class EnhancedChatRenderer implements ChatRenderer {
java.util.List<String> hoverLines = plugin.getConfig().getStringList("chat.hover.format");
if (hoverLines.isEmpty()) {
hoverLines = java.util.Arrays.asList(
"<gray>Игрок: <white>{player}",
"<gray>Мир: <green>{world}",
"<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>",
"<gradient:#87CEEB:#4169E1><bold>👤 Информация об игроке</bold></gradient>",
"",
"<yellow>▶ Клик: написать ЛС"
"<gray>🏷️ Имя: <white><bold>{player}</bold>",
"<gray>📶 Пинг: <yellow><bold>{ping}ms</bold>",
"<gray>❤️ Здоровье: <red><bold>{health}/20</bold>",
"<gray>🍖 Голод: <gold><bold>{food}/20</bold>",
"",
"<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>",
"<yellow>💬 <bold>Клик:</bold> <gray>написать личное сообщение"
);
}
@ -89,7 +105,7 @@ public class EnhancedChatRenderer implements ChatRenderer {
line = line.replace("{player}", player.getName())
.replace("{world}", player.getWorld().getName())
.replace("{ping}", String.valueOf(player.getPing()))
.replace("{gamemode}", player.getGameMode().name())
.replace("{gamemode}", getGameModeDisplay(player.getGameMode()))
.replace("{health}", String.valueOf(Math.round(player.getHealth())))
.replace("{food}", String.valueOf(player.getFoodLevel()));
@ -106,6 +122,18 @@ public class EnhancedChatRenderer implements ChatRenderer {
.clickEvent(ClickEvent.suggestCommand("/msg " + player.getName() + " "));
}
/**
* Получить красивое отображение игрового режима
*/
private String getGameModeDisplay(org.bukkit.GameMode gameMode) {
return switch (gameMode) {
case SURVIVAL -> "Выживание";
case CREATIVE -> "Творчество";
case ADVENTURE -> "Приключение";
case SPECTATOR -> "Наблюдатель";
};
}
private Component processUrls(Component message) {
String plainText = PlainTextComponentSerializer.plainText().serialize(message);
// Fixed regex: escape the dash in character class to avoid illegal range
@ -130,26 +158,50 @@ public class EnhancedChatRenderer implements ChatRenderer {
private Component processEmojis(Component message) {
Component result = message;
result = result.replaceText(builder -> builder.matchLiteral(":heart:").replacement("❤"));
// Основные символы
result = result.replaceText(builder -> builder.matchLiteral(":heart:").replacement("♥"));
result = result.replaceText(builder -> builder.matchLiteral(":star:").replacement("★"));
result = result.replaceText(builder -> builder.matchLiteral(":check:").replacement("✔"));
result = result.replaceText(builder -> builder.matchLiteral(":cross:").replacement("✖"));
result = result.replaceText(builder -> builder.matchLiteral(":check:").replacement("✓"));
result = result.replaceText(builder -> builder.matchLiteral(":cross:").replacement("✗"));
result = result.replaceText(builder -> builder.matchLiteral(":arrow:").replacement("→"));
result = result.replaceText(builder -> builder.matchLiteral(":skull:").replacement("☠"));
result = result.replaceText(builder -> builder.matchLiteral(":note:").replacement("♪"));
result = result.replaceText(builder -> builder.matchLiteral(":sun:").replacement("☀"));
result = result.replaceText(builder -> builder.matchLiteral(":moon:").replacement("☽"));
result = result.replaceText(builder -> builder.matchLiteral(":snowflake:").replacement("❄"));
result = result.replaceText(builder -> builder.matchLiteral(":fire:").replacement("🔥"));
result = result.replaceText(builder -> builder.matchLiteral(":fire:").replacement("▲"));
// Minecraft символы
result = result.replaceText(builder -> builder.matchLiteral(":diamond:").replacement("◆"));
result = result.replaceText(builder -> builder.matchLiteral(":sword:").replacement("⚔"));
result = result.replaceText(builder -> builder.matchLiteral(":pickaxe:").replacement("⛏"));
result = result.replaceText(builder -> builder.matchLiteral(":bow:").replacement("🏹"));
result = result.replaceText(builder -> builder.matchLiteral(":shield:").replacement("🛡"));
result = result.replaceText(builder -> builder.matchLiteral(":potion:").replacement("🧪"));
result = result.replaceText(builder -> builder.matchLiteral(":book:").replacement("📖"));
result = result.replaceText(builder -> builder.matchLiteral(":crown:").replacement("👑"));
result = result.replaceText(builder -> builder.matchLiteral(":gem:").replacement("💎"));
result = result.replaceText(builder -> builder.matchLiteral(":bow:").replacement("⌐"));
result = result.replaceText(builder -> builder.matchLiteral(":shield:").replacement("▣"));
result = result.replaceText(builder -> builder.matchLiteral(":potion:").replacement("⚗"));
result = result.replaceText(builder -> builder.matchLiteral(":book:").replacement("▤"));
result = result.replaceText(builder -> builder.matchLiteral(":crown:").replacement("♔"));
result = result.replaceText(builder -> builder.matchLiteral(":gem:").replacement("◊"));
result = result.replaceText(builder -> builder.matchLiteral(":emerald:").replacement("◈"));
result = result.replaceText(builder -> builder.matchLiteral(":gold:").replacement("◉"));
result = result.replaceText(builder -> builder.matchLiteral(":iron:").replacement("◎"));
// Дополнительные символы
result = result.replaceText(builder -> builder.matchLiteral(":thumbsup:").replacement("▲"));
result = result.replaceText(builder -> builder.matchLiteral(":thumbsdown:").replacement("▼"));
result = result.replaceText(builder -> builder.matchLiteral(":clap:").replacement("※"));
result = result.replaceText(builder -> builder.matchLiteral(":wave:").replacement("~"));
result = result.replaceText(builder -> builder.matchLiteral(":peace:").replacement("✌"));
result = result.replaceText(builder -> builder.matchLiteral(":ok:").replacement("◯"));
result = result.replaceText(builder -> builder.matchLiteral(":facepalm:").replacement("⌐_⌐"));
result = result.replaceText(builder -> builder.matchLiteral(":shrug:").replacement("¯\\_(ツ)_/¯"));
result = result.replaceText(builder -> builder.matchLiteral(":thinking:").replacement("?"));
result = result.replaceText(builder -> builder.matchLiteral(":laugh:").replacement("xD"));
result = result.replaceText(builder -> builder.matchLiteral(":cry:").replacement(":'("));
result = result.replaceText(builder -> builder.matchLiteral(":rage:").replacement(">:("));
result = result.replaceText(builder -> builder.matchLiteral(":cool:").replacement("B)"));
result = result.replaceText(builder -> builder.matchLiteral(":wink:").replacement(";)"));
return result;
}
}

View file

@ -1,84 +1,140 @@
# ╔══════════════════════════════════════════════════════════════════════════════╗
# ║ LoChat Chat Formats ║
# ║ Форматы чата ║
# ║ LoChat Beautiful Chat Formats ║
# ║ Красивые форматы чата ║
# ║ Версия: 1.5.5-1.20.1 ║
# ╚══════════════════════════════════════════════════════════════════════════════╝
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ ФОРМАТЫ ЧАТА │
# │ КРАСИВЫЕ ФОРМАТЫ ЧАТА │
# └─────────────────────────────────────────────────────────────────────────────┘
# Доступные плейсхолдеры:
# {player} - имя игрока
# {display_name} - отображаемое имя с градиентом
# {prefix} - префикс игрока
# {suffix} - суффикс игрока
# {world} - мир игрока
# {message} - сообщение
# {time} - время
# {date} - дата
# Все плейсхолдеры PlaceholderAPI
# Настройки отображения чата
chat:
# Включить красивые префиксы
beautiful_prefixes: true
formats:
# Глобальный чат
# Включить hover эффекты на никах
hover:
enabled: true
# Формат hover подсказки (поддерживает MiniMessage)
format:
- "<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>"
- "<gradient:#87CEEB:#4169E1><bold>👤 Информация об игроке</bold></gradient>"
- ""
- "<gray>🏷️ Имя: <white><bold>{player}</bold>"
- "<gray>📶 Пинг: <yellow><bold>{ping}ms</bold>"
- "<gray>❤️ Здоровье: <red><bold>{health}/20</bold>"
- "<gray>🍖 Голод: <gold><bold>{food}/20</bold>"
- ""
- "<gradient:#FFD700:#FFA500><bold>▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬</bold></gradient>"
- "<yellow>💬 <bold>Клик:</bold> <gray>написать личное сообщение"
# Настройки глобального чата
global:
enabled: true
format: "&#FFD700[G] {prefix}{display_name}&r: {message}"
hover:
- "<gray>Игрок: <white>{player}"
- "<gray>Мир: <green>{world}"
- "<gray>Пинг: <yellow>%player_ping%ms"
- ""
- "<yellow>▶ Клик: написать ЛС"
click:
action: "suggest_command"
value: "/msg {player} "
# Префикс глобального чата
prefix:
# Использовать эмодзи
emoji: "🌍"
# Текст с градиентом
text: "GLOBAL"
# Цвета градиента (от -> к)
gradient:
from: "#FFD700"
to: "#FF4500"
# Локальный чат
# Разделитель между префиксом и ником
separator:
text: " ▶ "
color: "#FFD700"
# Настройки локального чата
local:
enabled: true
format: "&#87CEEB[L] {prefix}{display_name}&r: {message}"
hover:
- "<gray>Игрок: <white>{player}"
- "<gray>Координаты: <yellow>{x}, {y}, {z}"
- "<gray>Расстояние: <green>%distance%м"
- ""
- "<yellow>▶ Клик: написать ЛС"
click:
action: "suggest_command"
value: "/msg {player} "
# Префикс локального чата
prefix:
# Использовать эмодзи
emoji: "📍"
# Текст с градиентом
text: "LOCAL"
# Цвета градиента (от -> к)
gradient:
from: "#87CEEB"
to: "#4169E1"
# Личные сообщения
private:
sent: "&7[→] &#87CEEBВы &7→ {display_name}&7: {message}"
received: "&7[←] {display_name} &7→ &#87CEEBВы&7: {message}"
hover:
- "<gray>Отправлено: <white>%time%"
- ""
- "<yellow>▶ Клик: ответить"
click:
action: "suggest_command"
value: "/reply "
# Разделитель между префиксом и ником
separator:
text: " ▶ "
color: "#87CEEB"
# Объявления
announcement:
format: "&#FF6B6B[ОБЪЯВЛЕНИЕ] <message>"
title:
enabled: true
title: "&#FF6B6BОБЪЯВЛЕНИЕ"
subtitle: "{message}"
fade-in: 10
stay: 60
fade-out: 10
actionbar:
enabled: true
format: "&#FF6B6B[ОБЪЯВЛЕНИЕ] {message}"
# Радиус локального чата (блоки)
radius: 100
# Системные сообщения
system:
join: "&#6BCB77+ {display_name} &#6BCB77присоединился к игре"
quit: "&#FF6B6B- {display_name} &#FF6B6Bпокинул игру"
death: "&#FF6B6B☠ {display_name} &#FF6B6B{death_message}"
# Настройки эмодзи
emojis:
# Включить обработку эмодзи
enabled: true
# Список доступных эмодзи (символы для Minecraft)
list:
# Основные
":heart:": "♥"
":star:": "★"
":check:": "✓"
":cross:": "✗"
":arrow:": "→"
":fire:": "▲"
":snowflake:": "❄"
":sun:": "☀"
":moon:": "☽"
# Minecraft
":diamond:": "◆"
":sword:": "⚔"
":pickaxe:": "⛏"
":bow:": "⌐"
":shield:": "▣"
":potion:": "⚗"
":book:": "▤"
":crown:": "♔"
":emerald:": "◈"
":gold:": "◉"
":iron:": "◎"
# Эмоции (текстовые)
":thumbsup:": "▲"
":thumbsdown:": "▼"
":clap:": "※"
":wave:": "~"
":ok:": "◯"
":thinking:": "?"
":laugh:": "xD"
":cry:": ":'("
":rage:": ">:("
":cool:": "B)"
":wink:": ";)"
# Настройки URL обработки
urls:
# Включить кликабельные ссылки
enabled: true
# Цвет ссылок
color: "#00BFFF"
# Подчеркивание
underlined: true
# Hover текст
hover_text: "🔗 Открыть ссылку: {url}"
# Настройки упоминаний (@player)
mentions:
# Включить упоминания
enabled: true
# Цвет упоминания
color: "#FFD700"
# Звук при упоминании
sound:
enabled: true
type: "BLOCK_NOTE_BLOCK_PLING"
volume: 1.0
pitch: 2.0
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ ФОРМАТЫ ПО ГРУППАМ │
@ -89,49 +145,42 @@ groups:
priority: 1000
prefix: "&#FF0000[OWNER]"
suffix: ""
format: "{prefix} {display_name}&r: {message}"
name-color: "&#FF0000"
admin:
priority: 900
prefix: "&#FF6B6B[ADMIN]"
suffix: ""
format: "{prefix} {display_name}&r: {message}"
name-color: "&#FF6B6B"
moderator:
priority: 800
prefix: "&#FFA726[MOD]"
suffix: ""
format: "{prefix} {display_name}&r: {message}"
name-color: "&#FFA726"
helper:
priority: 700
prefix: "&#87CEEB[HELPER]"
suffix: ""
format: "{prefix} {display_name}&r: {message}"
name-color: "&#87CEEB"
vip:
priority: 600
prefix: "&#FFD700[VIP]"
suffix: ""
format: "{prefix} {display_name}&r: {message}"
name-color: "&#FFD700"
premium:
priority: 500
prefix: "&#6BCB77[PREMIUM]"
suffix: ""
format: "{prefix} {display_name}&r: {message}"
name-color: "&#6BCB77"
default:
priority: 0
prefix: ""
suffix: ""
format: "{display_name}&r: {message}"
name-color: "&#FFFFFF"
# ┌─────────────────────────────────────────────────────────────────────────────┐
@ -151,14 +200,9 @@ special:
volume: 1.0
pitch: 1.0
# Формат для эмодзи голов
head-emoji:
format: ":head_{player}:"
max-per-message: 3
# Формат для ссылок
url:
format: "<click:open_url:'{url}'><hover:show_text:'<gray>Открыть ссылку'><u>{url}</u></hover></click>"
format: "<click:open_url:'{url}'><hover:show_text:'<gray>🔗 Открыть ссылку'><u><#00BFFF>{url}</u></hover></click>"
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ НАСТРОЙКИ ОТОБРАЖЕНИЯ │
@ -184,32 +228,3 @@ display:
# Цвет сообщений по умолчанию
default-message-color: "&#FFFFFF"
# ┌─────────────────────────────────────────────────────────────────────────────┐
# │ ИНТЕГРАЦИИ │
# └─────────────────────────────────────────────────────────────────────────────┘
integrations:
# PlaceholderAPI
placeholderapi:
enabled: true
# LuckPerms
luckperms:
enabled: true
use-prefix: true
use-suffix: true
# Vault
vault:
enabled: true
# DiscordSRV
discordsrv:
enabled: false
format: "**{player}**: {message}"
# Dynmap
dynmap:
enabled: false
format: "{player}: {message}"