ZLDiscord v — Документация
Введение
ZLDiscord — универсальный плагин для Paper 1.16.5–1.21.x, интегрирующий Minecraft с Discord. Встроенный шаблонизатор, LongPoll-бот, кастомные команды, голосования, DataStore и полная поддержка PlaceholderAPI.
Установка
- Скопировать
ZoLiryzik.jarвplugins/ - Запустить LongPoll-бота:
node longpoll-server.js & - Перезапустить сервер (stop → start, не /reload)
- Настроить
config.yml: Discord Token, Guild ID, роли - Подключить LongPoll:
/zlongpoll create demo http://localhost:17523/poll secret 25
v1.4 База данных SQLite с авто-миграцией — настройка не требуется. Безопасная перезагрузка плагина через /zreload без перезапуска сервера.
Команды
/zevent — Голосование
/zevent "Название" "команда" "время" "channel_id" [route] [resolve-now]
- Название — заголовок embed (поддерживает
%placeholder%) - команда — Minecraft-команда консоли при победе ✅
- время — длительность:
5s,10m,1h - channel_id — ID текстового канала Discord
После таймера подсчитываются ✅ / ❌. При победе ✅ — выполняется команда.
- route — сервер для выполнения:
player/main/ имя сервера | только в дискорд сервере - resolve-now —
true(по умолч.) /false.false= плейсхолдеры резолвятся при завершении голосования, а не при создании
/zcc — Кастомные команды
/zcc list — список команд
/zcc run <name> — выполнить
/zcc create <name> — создать (\n для новой строки)
/zcc remove <name> — удалить
/zcc reload — перезагрузить
/zcc info <name> — инфо о команде (шаблон, кулдаун)
/zcc prefix discord <p> — изменить префикс Discord
/zcc prefix mc <p> — изменить префикс MC
/zlink / /zunlink — Привязка Discord
/zlink — получить код в Minecraft
/unlink — отвязать в Discord (ЛС бота)
/zembed — Embed-сообщение
/zembed "имя" "заголовок" "описание" "channel_id" [картинка] [миниатюра] [футер] [иконка_футера]
Создаёт embed в Discord, сохраняет messageId. PAPI
/zembedmanage — Управление embed
/zembedmanage delete <имя>
/zembedmanage edit_title <имя> "новый заголовок"
/zembedmanage edit_description <имя> "новое описание"
/zattr — DataStore
/zattr get <bot|member|player> <key> [player]
/zattr set <bot|member|player> <key> <value> [player]
/zattr inc|dec <...> <key> <amount> [player]
/zattr list <bot|member|player> [player]
/zlongpoll — LongPoll
/zlongpoll create <name> <url> <key> [wait]
/zlongpoll list
/zlongpoll remove <name>
/zlongpoll reload
/zstatus — Статус бота
/zstatus — показать статус
/zstatus set <text> — текст статуса
/zstatus settype <type> — тип: playing/watching/listening/competing
/zstatus reload — перезагрузить bot_status.yml
/zstatus interval <sec> — интервал смены статуса
v1.4 /zsync — Групповая синхронизация
/zsync reload — перезагрузить group_sync.yml
/zsync status — показать статус синхронизации
Синхронизирует роли Discord с группами LuckPerms. Назначает одну роль Discord на основе группы игрока в LuckPerms (с учётом приоритета). Настройка в group_sync.yml.
v1.4 /zprefix — Префикс команд
/zprefix discord <prefix> — изменить префикс Discord slash-команд
/zprefix mc <prefix> — изменить префикс MC команд
Меняет префикс команд Minecraft (z по умолчанию) и Discord (z! по умолчанию). Настройки в config.yml → minecraft-command-prefix, discord-command-prefix, discord-slash-command-prefix.
v1.4 /zreload — Перезагрузка
/zreload
Безопасная перезагрузка конфигурации плагина без перезапуска сервера. Перечитывает config.yml, кастомные команды и LongPoll подключения.
v1.4 Управление ролями Discord
/rolegive <member> <role> — выдать роль участнику
/roleremove <member> <role> — забрать роль у участника
/rolemenu — открыть меню выбора ролей
/roletoggle [member] [role] — переключить роль
/rolemenu— открывает панель выбора ролей в Discord (настройка вconfig.yml)/roletoggle— если роль есть — убирает, если нет — выдаёт
Команды в Discord
Prefix Текстовые команды в Discord используют префикс z! по умолчанию. Меняется в config.yml → discord-command-prefix.
/zevent— создать голосование (роли embed-creator)z!embed— кнопка для создания Embed/link <code>— привязать (ЛС бота)/unlink— отвязать (ЛС бота)/zcc reload— перезагрузить кастомные команды/zcc list— список кастомных команд/zcc prefix— управление префиксом- Slash-команды из
custom_commands.ymlрегистрируются автоматически - Текстовые команды из
custom_commands.yml— через префиксz!(например,z!warn,z!report)
Пермишены
| Пермишен | Описание |
|---|---|
zoliryzik.link v1.4 zoliryzik.zlink | Привязка аккаунта |
zoliryzik.unlink v1.4 zoliryzik.zunlink | Отвязка аккаунта |
zoliryzik.event v1.4 zoliryzik.use | Создание голосования |
zoliryzik.embed v1.4 zoliryzik.zembed | Создание embed |
zoliryzik.embed_manage v1.4 zoliryzik.zembed_manage | Управление embed |
zoliryzik.cc | Кастомные команды |
zoliryzik.attr v1.4 zoliryzik.attr.get | DataStore атрибуты |
zoliryzik.status | Статус бота |
zoliryzik.longpoll | LongPoll подключения |
zoliryzik.sync | Синхронизация ролей |
zoliryzik.prefix | Изменение префикса |
zoliryzik.reload | Перезагрузка плагина |
zoliryzik.rolegive | Выдача роли Discord |
zoliryzik.roleremove | Забрать роль Discord |
zoliryzik.rolemenu | Меню выбора ролей |
zoliryzik.roletoggle | Переключение роли |
zoliryzik.admin | Админ-доступ (все команды) |
Кастомные команды
Файл custom_commands.yml:
commands:
hello:
file: "commands/hello.yml"
description: "Приветствие"
cooldown: 10
enabled: true
scope: all # all / minecraft / discord
permission: zoliryzik.hello
permission-message: "&cНет прав"
command_mc: hello # имя в майнкрафте
command_ds: hello # имя в дискорде
aliases_mc: ["h"]
aliases_ds: ["h"]
discord-roles: ["role_id_1", "role_id_2"]
Поддерживается вложенность папок: commands/lp/lp.yml
Пример hello.yml
<~ args[0] ~>, привет с сервера!
Пример fly.yml (условия, аргументы, PAPI)
<set target = args[0]>
<require target != null return "Укажи ник игрока">
<set mode = args[1]>
<if mode == null or mode == "">
<set mode = "toggle">
</if>
<if mode == "on">
<do mc.command("zflytoggle " + target + " on")>
<~ target ~>: полёт &aвключён
<elseif mode == "off">
<do mc.command("zflytoggle " + target + " off")>
<~ target ~>: полёт &cвыключен
<else>
<do mc.command("zflytoggle " + target)>
<~ target ~>: полёт переключён
</if>
Система шаблонов
Переменные
| Переменная | Где | Описание |
|---|---|---|
args | всегда | List аргументов |
_args_raw | всегда | Строка аргументов |
_cmd_name | всегда | Имя команды |
_lang | всегда | Язык: ru/en |
mc_online | всегда | Игроков онлайн |
mc_max_players | всегда | Макс. игроков |
mc_tps | всегда | TPS |
mc_motd | всегда | MOTD |
_player_name | Minecraft | Имя игрока |
_player_uuid | Minecraft | UUID |
_player_world | Minecraft | Мир |
_discord_member_id | Discord | ID участника |
_discord_member_name | Discord | Имя |
_discord_member_nick | Discord | Никнейм |
_discord_channel_id | Discord | ID канала |
_discord_channel_name | Discord | Название канала |
_discord_guild_id | Discord | ID гильдии |
_discord_guild_name | Discord | Название гильдии |
_mentioned_user_id | Discord | ID упомянутого |
_mentioned_user_name | Discord | Имя упомянутого |
Теги
| Тег | Описание |
|---|---|
<~ expr ~> | Вывести значение |
<set var = expr> | Присвоить переменную |
<if cond>...<else>...</if> | Условие |
<for var in list>...</for> | Цикл |
<do action(...)> | Выполнить действие |
<require cond return "msg"> | Проверка с ошибкой |
<return "msg"> | Выход с сообщением |
<global var = expr> | Глобальная переменная |
<# comment #> | Комментарий |
v1.4 В условиях <if> теперь поддерживаются скобки: <if (a == 1 or b == 2) and c == 3>
Функции
Строки: lower, upper, capitalize, trim, title, replace(a,b,s), split(sep,s), length, format, after(N)
Проверки: defined, empty, not, number, iterable, even, odd, contains, startsWith, endsWith, typeof
Математика: abs, round, number_format, random(min,max), random_hex, random_uuid
Коллекции: first, last, reverse, slice, sort, shuffle, batch, concat, join, keys, values, default
PAPI: papi("placeholder" [, player])
DataStore: getattribute(key), member.getattribute(key), player.getattribute(key), bot.getattribute(key), find_player_by_session(id)
HTTP: http_get(url), http_post(url, body|key,val...), http_put, http_delete, http_patch, http_code(resp), http_body(resp), http_header(name,val), http_bearer(token), json_parse(str)
Действия (<do>)
| Действие | Описание |
|---|---|
mc.command("cmd") | Выполнить команду (консоль/игрок) |
mc.broadcast("msg") | Отправить в чат (& для цвета) |
mc.give("player","item") | Выдать предмет |
discord.send(channelId,"text") | Сообщение в Discord |
discord.embed(...) | Embed (title, description, color, fields, buttons, reactions) |
discord.role_add/give(memberId, roleId) | Добавить роль |
discord.role_remove/delete(memberId, roleId) | Удалить роль |
discord.auto_delete() | Авто-удаление сообщения с командой |
discord.open_modal("name") | Открыть модальное окно |
bot.setstatus("online/dnd/idle") | Статус бота |
bot.setstatustext("текст") | Текст статуса |
Chain API
guild.getChannel("id").createEmbed().withTitle("...").withColor("#hex").withField("n","v",true).send()
Статус бота
Файл bot_status.yml:
enabled: true
type: "playing" # playing / watching / listening / competing / custom
text: "с сервером"
LongPoll Bot API
Node.js-бот на http://localhost:17523. Аутентификация: Authorization: Bearer secret.
| Метод | Endpoint | Тело |
|---|---|---|
| POST | /event | {"type":"...", ...} |
| POST | /api/config | {"key":"value"} |
| GET | /api/script?type=X | — |
| POST | /api/script?type=X | {"script":"..."} |
LongPoll скрипты
Путь: longpoll/papca/<connection>/<type>.yml
| Переменная | Описание |
|---|---|
_event | Map со всеми полями |
_event.type | Тип события |
_event.player, ... | Поля из JSON |
_conn_name | Имя подключения |
Важно Только <do action(...)>, НЕ <action(...)>.
Пример donate.yml
<if !defined(_event.nickname)>
<do mc.command("say", "Donate: no nickname in event")>
<else>
<set _nick = _event.nickname>
<set _amount = _event.amount>
<do mc.command("give " + _nick + " diamond " + (_amount / 100))>
<if _lang == "ru">
<do mc.broadcast("&a🎉 Игрок " + _nick + " задонатил &e" + _amount + " &aи получил " + (_amount / 100) + " алмазов!")>
<else>
<do mc.broadcast("&a🎉 Player " + _nick + " donated &e" + _amount + " &aand got " + (_amount / 100) + " diamonds!")>
</if>
<do player.getAttribute("donations").increment(_amount)>
</if>
PlaceholderAPI
- Игрок — от имени отправителя
- Консоль — от первого онлайн
- papi("x", "Nick") — для любого игрока
- lang_*.yml —
%placeholder%работает напрямую в сообщениях команд (getMessage(path, sender))
| Плейсхолдер | Описание |
|---|---|
%zoliryzik_in_vc% | Статус в голосовом канале: "В голосовом чате" / "Не в голосовом чате" / "Не привязан" |
%zoliryzik_attr_member_<key>% | Атрибут Discord-участника из DataStore по ключу |
%zoliryzik_attr_player_<key>% | Атрибут игрока из DataStore по ключу |
%zoliryzik_attr_bot_<key>% | Глобальный атрибут бота из DataStore по ключу |
v1.4 Проверка ролей
| Плейсхолдер | Описание |
|---|---|
%zoliryzik_role_<role_id>% | "true" если игрок имеет ЛЮБУЮ из указанных ролей (OR). Несколько ID через запятую. |
%zoliryzik_roles_<role_id>% | "true" если игрок имеет ВСЕ указанные роли (AND). Несколько ID через запятую. |
Пример: %zoliryzik_role_123456,789012% — true если есть роль 123456 ИЛИ 789012.
Пример: %zoliryzik_roles_123456,789012% — true если есть роль 123456 И 789012.
Конфигурация
Загрузка...
Переменные окружения
| Переменная | Описание |
|---|---|
DISCORD_TOKEN | Токен Discord бота |
LONGPOLL_KEY | Ключ API (умолч. secret) |
LONGPOLL_PORT | Порт (умолч. 17523) |
GroupSync — Синхронизация ролей
Файл group_sync.yml. Синхронизирует группы LuckPerms с ролями Discord.
- Приоритет: снизу вверх. Последняя роль = высший приоритет.
- Игрок может иметь несколько групп LP, но в Discord — только одну роль (наивысший приоритет).
sync-on-discord-edit: true— при ручной смене роли в Discord обновляется группа LP.
enabled: true
sync-on-discord-edit: true
group-roles:
default: "role_id_1" # низший приоритет
vip: "role_id_2"
premium: "role_id_3"
admin: "role_id_4" # высший приоритет
Reactions — Реакции
Файл reactions.yml. Автоматические действия при добавлении/удалении реакций.
reactions:
welcome:
type: "reaction_add"
channel_id: "000000000000000000"
message_id: "any"
emoji: "✅"
role_id: "000000000000000000"
remove_on_unreact: true
upvote:
type: "reaction_add"
channel_id: "any"
message_id: "any"
emoji: "⭐"
command: "mc.command('say '+_discord_member_name+' gave a star')"
type—reaction_addилиreaction_removechannel_id— ID канала или"any"message_id— ID сообщения или"any"role_id— роль для выдачи/удаленияcommand— шаблон команды для выполненияremove_on_unreact— убрать роль при снятии реакции
Modals — Модальные окна
Файл modals.yml. Discord Modal — всплывающее окно с полями ввода.
modals:
report:
title: "Submit Report"
command: "report"
fields:
- label: "Player Name"
style: "short"
placeholder: "Enter nickname"
required: true
min_length: 1
max_length: 32
- label: "Reason"
style: "paragraph"
placeholder: "Describe the reason"
required: true
min_length: 10
max_length: 500
Вызывается из шаблона: <do discord.open_modal("report")>
style—short(одна строка) /paragraph(много строк)- Поля доступны в шаблоне как
{field_label}
Banned Commands — Чёрный список
Файл banned_commands.yml.
Два отдельных списка запрещённых команд:
zevent-blacklist
Модераторы и ивенторы не смогут создать голосование для этих команд.
zevent-blacklist:
- stop
- restart
- shutdown
- reload
- plugman
- op
- deop
- ban
- kick
- gamemode
mc-command-blacklist
Команды, которые нельзя выполнить через <do mc.command(...)>. Защита от злоупотребления шаблонизатором.
mc-command-blacklist:
# Серверные команды
- stop
- restart
- shutdown
- reload
- plugman
# Права игроков
- op
- deop
- ban
- pardon
- ban-ip
- pardon-ip
# Управление сервером
- whitelist
- save-all
- save-off
- save-on
- force-upgrade
- version
- plugins
- help
# Геймод и читы
- gamemode
- gm
- gmc
- gms
- gma
- gmsp
- effect
- enchant
- tp
- teleport
- tphere
- tppos
- spawnpoint
- setworldspawn
- time
- weather
- difficulty
- xp
# Опасные операции
- execute
- run
- as
- data
- datapack
- function
- macro
Кастомные плейсхолдеры
Файл placeholders.yml. Создание собственных плейсхолдеров %zoliryzik_<name>%.
placeholders:
server_type:
description: "Тип сервера"
value: "Survival"
online_info:
description: "Информация об онлайне"
template: "&a❤ &f<~ mc_online ~>/<~ mc_max_players ~>"
player_guild_name:
description: "Имя гильдии игрока"
template: "<~ papi('%some_plugin_guild%', _player_name) ~>"
requires_player: true
value— статическое значениеtemplate— динамический шаблон (поддерживает<~ ~>)requires_player— привязка к игроку из контекста
Примеры скриптов
Примеры для отправки событий в LongPoll-бот из внешних скриптов.
Python
import requests, json
URL = "http://localhost:17523/event"
HEADERS = {
"Authorization": "Bearer secret",
"Content-Type": "application/json"
}
# Отправить событие donate
event = {
"type": "donate",
"nickname": "Player123",
"amount": 1500,
"product": "Diamond Pack"
}
r = requests.post(URL, headers=HEADERS, json=event)
print("Status:", r.status_code, r.json())
# Отправить событие kick
event = {
"type": "kick",
"nickname": "Griefer",
"reason": "Spam",
"moderator": "Admin"
}
r = requests.post(URL, headers=HEADERS, json=event)
print("Status:", r.status_code, r.json())
Node.js
const URL = "http://localhost:17523/event";
const HEADERS = {
"Authorization": "Bearer secret",
"Content-Type": "application/json"
};
// Отправить событие donate
fetch(URL, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({
type: "donate",
nickname: "Player123",
amount: 1500,
product: "Diamond Pack"
})
}).then(r => r.json()).then(console.log);
// Отправить событие kick
fetch(URL, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({
type: "kick",
nickname: "Griefer",
reason: "Spam",
moderator: "Admin"
})
}).then(r => r.json()).then(console.log);
curl
curl http://localhost:17523/event -X POST \
-H "Authorization: Bearer secret" \
-H "Content-Type: application/json" \
-d '{"type":"donate","nickname":"Player123","amount":1500}'
curl http://localhost:17523/event -X POST \
-H "Authorization: Bearer secret" \
-H "Content-Type: application/json" \
-d '{"type":"kick","nickname":"Griefer","reason":"Spam","moderator":"Admin"}'
Примеры
LP команда из Minecraft
<set _ = http_header("Authorization", "Bearer secret")>
<set _type = args[0]>
<set _resp = http_post("http://localhost:17523/event",
"type", _type, "player", _player_name, "world", _player_world,
"cmd", _cmd_name, "args", _args_raw)>
<do mc.broadcast("&a[LP] &f" + _type + " &a✓")>
Donate-уведомление
<if _event.amount >= 5000>
<do mc.broadcast("&a&l⭐ Мега-донат от &e" + _event.nickname)>
<else>
<do mc.broadcast("&a❤ " + _event.nickname + " задонатил &e" + _event.amount)>
</if>
Информация об игроке (info.yml)
<set target = args[0]>
<if target == null or target == "">
<set target = _player_name>
</if>
📊 Информация о <~ target ~>
├ Уровень: <~ papi("%level%", target) ~>
├ Здоровье: <~ papi("%player_health%", target) ~>
├ Мир: <~ papi("%player_world%", target) ~>
└ Онлайн: <~ mc_online ~>/<~ mc_max_players ~>
Report (Discord-команда)
<set target = args[0]>
<set reason = after(1)>
<require target != null and reason != "" return "Укажи ID или упоминание нарушителя и причину">
Был отправлен репорт на участника <~ target ~>:
<~ reason ~>
<do discord.send(_discord_channel_id, format("%s, Ваш репорт успешно отправлен!", _discord_member_nick))>
Телепортация по заявке (Discord)
<set who = args[0]>
<require who != null return "Укажи ник игрока">
<require hasRole("MODERATOR_ROLE_ID") return "Нет прав на телепортацию">
<do mc.command("tp " + _player_name + " " + who)>
<do discord.send(_discord_channel_id,
"⚡ " + _player_name + " телепортировался к " + who)>
Бан через Discord
<require hasRole("ADMIN_ROLE_ID") return "Только для администрации">
<set player = args[0]>
<set reason = after(1)>
<require player != null return "Укажи игрока">
<require reason != "" return "Укажи причину бана">
<do mc.command("ban " + player + " " + reason)>
<do discord.send(_discord_channel_id,
"🔨 " + player + " забанен. Причина: " + reason)>
Важно hasRole() проверяет роли Discord, работает только в Discord-командах. Для Minecraft используйте стандартные пермишены.
Список онлайн (из Discord)
Сейчас на сервере: <~ mc_online ~>/<~ mc_max_players ~>
TPS: <~ mc_tps ~>
Рассылка по каналам
<set msg = after(0)>
<require msg != "" return "Напиши сообщение после команды">
<do discord.send("CHANNEL_ID_1", msg)>
<do discord.send("CHANNEL_ID_2", msg)>
<do mc.broadcast("&a📢 Объявление отправлено в Discord")>
Проверка привязки перед выдачей
<set linked = getattribute("linked_" + _player_uuid)>
<if linked == null or linked == "">
<do mc.command("msg " + _player_name + " Привяжи аккаунт: /zlink")>
<else>
<do mc.command("give " + _player_name + " diamond 1")>
<do mc.broadcast("&a" + _player_name + " получил алмаз за привязку!")>
</if>
Статус бота по таймеру
В bot_status.yml можно использовать плейсхолдеры:
enabled: true
type: "playing"
text: "на сервере | <~ mc_online ~> игроков"