ZLDiscord v1.2 — Документация


Введение

ZLDiscord — универсальный плагин для Paper 1.16.5–1.21.x, интегрирующий Minecraft с Discord. Встроенный шаблонизатор, LongPoll-бот, кастомные команды, голосования, DataStore и полная поддержка PlaceholderAPI.


Установка

  1. Скопировать ZoLiryzik.jar в plugins/
  2. Запустить LongPoll-бота: node longpoll-server.js &
  3. Перезапустить сервер (stop → start, не /reload)
  4. Настроить config.yml: Discord Token, Guild ID, роли
  5. Подключить LongPoll: /zlongpoll create demo http://localhost:17523/poll secret 25

Команды

/zevent — Голосование

/zevent "Название" "команда" "время" "channel_id"
  • Название — заголовок embed (поддерживает %placeholder%)
  • команда — Minecraft-команда консоли при победе ✅
  • время — длительность: 5s, 10m, 1h
  • channel_id — ID текстового канала Discord

После таймера подсчитываются ✅ / ❌. При победе ✅ — выполняется команда.

/zcc — Кастомные команды

/zcc list             — список команд
/zcc run <name>       — выполнить
/zcc create <name>    — создать (\n для новой строки)
/zcc remove <name>    — удалить
/zcc reload           — перезагрузить

/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

Команды в Discord

Prefix Текстовые команды в Discord имеют фиксированный префикс z! (например, z!hello, z!info). Поменять его нельзя.

  • /zevent — создать голосование (роли embed-creator)
  • !embed — кнопка для создания Embed
  • /link <code> — привязать (ЛС бота)
  • /unlink — отвязать (ЛС бота)
  • Slash-команды из custom_commands.yml регистрируются автоматически
  • Текстовые команды из custom_commands.yml — через префикс z! (например, z!warn, z!report)

Кастомные команды

Файл 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        # имя в дискорде (префикс z! — z!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_nameMinecraftИмя игрока
_player_uuidMinecraftUUID
_player_worldMinecraftМир
_discord_member_idDiscordID участника
_discord_member_nameDiscordИмя
_discord_member_nickDiscordНикнейм
_discord_channel_idDiscordID канала
_discord_channel_nameDiscordНазвание канала
_discord_guild_idDiscordID гильдии
_discord_guild_nameDiscordНазвание гильдии
_mentioned_user_idDiscordID упомянутого
_mentioned_user_nameDiscordИмя упомянутого

Теги

ТегОписание
<~ 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 #>Комментарий

Функции

Строки: 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)Удалить роль
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

ПеременнаяОписание
_eventMap со всеми полями
_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") — для любого игрока
ПлейсхолдерОписание
%zoliryzik_in_vc%Статус в голосовом канале: "В голосовом чате" / "Не в голосовом чате" / "Не привязан"
%zoliryzik_attr_member_<key>%Атрибут Discord-участника из DataStore по ключу
%zoliryzik_attr_player_<key>%Атрибут игрока из DataStore по ключу
%zoliryzik_attr_bot_<key>%Глобальный атрибут бота из DataStore по ключу

Конфигурация

Загрузка...

Переменные окружения

ПеременнаяОписание
DISCORD_TOKENТокен Discord бота
LONGPOLL_KEYКлюч API (умолч. secret)
LONGPOLL_PORTПорт (умолч. 17523)

Примеры скриптов

Примеры для отправки событий в 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))>

Диагностика

/zdiag (ZDiag) — 12 тестов: бот, каналы, роли, LongPoll, атрибуты, HTTP, шаблоны, PAPI, права.