BetonQuest: настройка квестов на Minecraft сервере (гайд 2026)
Если в RPG-проекте нужны не "убей 10 зомби", а полноценные ветки диалогов с NPC, условиями и наградами, BetonQuest закрывает эту задачу декларативным YAML без единой строки кода. Ниже разберём установку, формат пакетов 2.x, работу objectives и conditions, интеграцию с Citizens и DecentHolograms, миграцию со старой версии и узкие места по производительности.
Что такое BetonQuest и зачем декларативные квесты
BetonQuest - это плагин для Bukkit-совместимых ядер, который описывает квесты через текстовые YAML-файлы. Никаких скриптов, никаких компиляторов: пишешь конфиг, перезагружаешь плагин, квест работает. Исходники и документация лежат на github.com/BetonQuest/BetonQuest и docs.betonquest.org.
Философия плагина простая: квест - это связка из четырёх элементов.
- Objectives - задачи, которые игрок выполняет (убить моба, скрафтить предмет, дойти до точки)
- Conditions - условия, которые проверяются (есть ли тег, какой класс, какой уровень)
- Events - действия, которые сервер выполняет в ответ (выдать предмет, телепортнуть, поставить тег)
- Conversations - дерево диалогов с NPC, в узлах которого живут условия и события
В сумме получается граф состояний игрока, где переходы между нодами управляются тегами и поинтами. Никакого жёсткого кода для веток "если игрок спас принцессу, то деревенский кузнец даёт скидку" не нужно: всё описывается условиями tag и событиями tag add.
Альтернативы есть. Quests Plugin проще для старта, но потолок у него низкий: сложные ветки и условия туда не вписать. ZNPCsPlus + ZSkriptCore работают, но требуют Skript-кода. Если нужен взрослый RPG-сервер с сотнями нод диалогов и сейв-системой между сессиями - BetonQuest стоит брать сразу.
Установка и зависимости
BetonQuest 2.x работает на Paper 1.21+ и требует Java 21. Старые ядра (1.16-1.20) поддерживает ветка 1.x, но новые фичи туда уже не бэкпортируются.
cd plugins/
wget -O BetonQuest.jar https://github.com/BetonQuest/BetonQuest/releases/latest/download/BetonQuest.jar
# либо качай с hangar.papermc.io/BetonQuest/BetonQuest
После старта сервера появится папка plugins/BetonQuest/ со структурой:
plugins/BetonQuest/
├── config.yml
├── messages.yml
├── menuConfig.yml
├── lang/
└── QuestPackages/
└── default/
├── package.yml
├── events.yml
├── conditions.yml
├── objectives.yml
├── conversations/
└── journal.yml
Опциональные интеграции, которые ставят почти все:
- Citizens - чтобы привязывать диалоги к видимым NPC, а не к стоящим скелетам
- DecentHolograms - голограммы над NPC и в точках интереса
- LuckPerms - выдача прав через события
permission - PlaceholderAPI - подстановка
%betonquest_*%в чат, сайдбар, голограммы - MythicMobs - спавн боссов событиями BetonQuest и условия по убитому MythicMob
- ProtocolLib - нужен для нескольких подсистем, ставится почти всегда
После любых правок YAML вызывайте /q reload. Это перечитывает все пакеты без рестарта сервера. Если в чате появилось красное сообщение про ошибку парсинга - открывайте logs/latest.log, BetonQuest пишет туда полный путь к проблемной строке.
Package layout в 2.x: главное отличие от 1.x
В версии 2.x пакеты стали полноценными директориями. Раньше один файл package.yml хранил всё: события, условия, objectives, диалоги. Теперь наоборот - всё разнесено по подпапкам, и любой файл внутри пакета автоматически собирается в общую конфигурацию.
QuestPackages/
└── city_quests/
├── package.yml # метаданные пакета
├── events/
│ ├── reward.yml
│ └── teleport.yml
├── conditions/
│ └── access.yml
├── objectives/
│ └── main_chain.yml
├── conversations/
│ ├── innkeeper.yml
│ └── blacksmith.yml
└── journal.yml
Это сильно облегчает жизнь, когда квестов 50+. Можно держать каждый сюжетный блок в своём файле, а саб-пакеты делать через вложенные папки: QuestPackages/main/chapter_one/ и QuestPackages/main/chapter_two/ будут двумя отдельными пакетами с именами main-chapter_one и main-chapter_two.
Файл package.yml минимально выглядит так:
package:
enabled: true
priority: 0
variables:
city_name: "Нортхэвен"
reward_amount: 200
Переменные из variables: дальше доступны как %city_name% в любом тексте диалога или сообщения.
Первый диалог: пример conversation YAML
Создадим файл QuestPackages/city_quests/conversations/innkeeper.yml. Это диалог с трактирщиком, который даёт квест на крыс в подвале.
conversations:
innkeeper:
quester: "&6Трактирщик"
first: greeting
NPC_options:
greeting:
text: "Странные звуки из подвала... Не глянешь, что там?"
conditions: "!quest_started,!quest_done"
pointers: accept,ask_reward,decline
already_started:
text: "Ну как, разобрался с крысами?"
conditions: "quest_started,!rats_killed"
pointers: still_busy,decline
give_reward:
text: "Спасибо, держи! За мной не заржавеет."
conditions: "rats_killed,!quest_done"
events: pay_reward,close_quest
after_done:
text: "Заходи ещё, путник."
conditions: "quest_done"
player_options:
accept:
text: "Гляну. Где вход?"
events: start_quest,give_torch
pointer: accepted
ask_reward:
text: "А что за это будет?"
pointer: reward_info
decline:
text: "Не сейчас."
still_busy:
text: "Ещё ищу их."
reward_info:
text: "200 монет и ужин за счёт заведения."
pointer: greeting
Что тут происходит:
quester- имя, которое игрок видит в окне диалогаfirst- стартовый узел NPC, с которого начинается разговорNPC_options- реплики NPC. У каждой свои условия и список указателей на варианты игрокаplayer_options- реплики игрока. Каждая может запускать события и переходить дальше поpointerconditions- какие условия должны выполниться, чтобы реплика показалась. Префикс!инвертируетevents- срабатывают, когда реплика выбрана
Пока не описали accept, quest_started, pay_reward - сервер ругнётся при /q reload. Двигаемся к objectives и events.
Objectives и conditions: задачи и проверки
Объектива в QuestPackages/city_quests/objectives/main_chain.yml:
objectives:
hunt_rats:
type: mobkill
conditions: ""
events: rats_done
instruction: mobkill RAT 5 events:rats_done notify
reach_cellar:
type: location
instruction: location 100;64;200;world 3 events:cellar_reached
craft_torch:
type: craft
instruction: craft TORCH 4
Тип mobkill использует MythicMob с id RAT, поэтому в этом примере нужен MythicMobs. Если хочется ванильного зомби - заменяйте на mobkill ZOMBIE 5. Параметр notify показывает игроку прогресс через ActionBar.
Условия в conditions.yml:
conditions:
quest_started:
type: tag
instruction: tag rats_quest_started
rats_killed:
type: objective
instruction: objective hunt_rats
quest_done:
type: tag
instruction: tag rats_quest_done
has_torch:
type: item
instruction: item torch:1
is_warrior:
type: variable
instruction: variable %class% warrior
Условия читаются как "проверка сервера в момент клика". Если игрок выбирает реплику accept, BetonQuest проверяет все условия родительского узла NPC, и только при их выполнении реплика отрисуется.
Events и tags: что плагин делает в ответ
События - это то, что сервер запускает на действие игрока или по таймеру. Файл events.yml:
events:
start_quest:
type: tag
instruction: tag add rats_quest_started
pay_reward:
type: give
instruction: give emerald:5,gold_ingot:10
close_quest:
type: folder
instruction: folder mark_done,remove_objective,journal_finished
mark_done:
type: tag
instruction: tag add rats_quest_done
remove_objective:
type: objective
instruction: objective remove hunt_rats
give_torch:
type: give
instruction: give torch:4
journal_finished:
type: journal
instruction: journal add rats_finished
teleport_cellar:
type: teleport
instruction: teleport 100;64;200;world
rats_done:
type: notify
instruction: notify {en}Rats cleared!{ru}Крысы уничтожены! io:Title
Хитрость с folder - это контейнер из нескольких событий, которые отрабатывают по очереди. Используется, чтобы не дублировать вызовы в каждой ветке диалога.
Теги (tag) - это самый надёжный способ запоминать состояние квеста. Они хранятся в БД плагина (SQLite по умолчанию или MySQL, если переключили в config.yml) и переживают рестарт сервера. На активном проекте обязательно переключайте storage на MySQL, чтобы не терять прогресс игроков при крашах SQLite.
Интеграция с Citizens и DecentHolograms
Чтобы привязать диалог к Citizens NPC, в package.yml добавляется блок npcs:. ID NPC берётся командой /npc select -> /npc info.
npcs:
"12": innkeeper
"13": blacksmith
"14": village_elder
Теперь по правому клику на NPC с ID 12 откроется диалог innkeeper. Никакого npc.yml отдельно не нужно, всё лежит в пакете.
DecentHolograms ставит голограммы условно, например иконку "?" над NPC, который выдаёт квест:
events:
show_marker:
type: hologram
instruction: hologram quest_marker
hide_marker:
type: hologram
instruction: hologram quest_marker hide
Сама голограмма создаётся через /dh create quest_marker и привязывается командой /dh attach quest_marker npc_12 0 2.5 0. BetonQuest управляет только видимостью.
Журнал и UI игрока
Журнал - это книга, которая описывает игроку, что он сейчас делает и что уже выполнил. Записи в journal.yml:
journal:
rats_started: "&7В подвале трактира кто-то возится. Трактирщик попросил разобраться с крысами."
rats_finished: "&aКрысы уничтожены, награда получена."
blacksmith_intro: "&7Кузнец ищет подмастерье."
Записи добавляются событием journal add <id> и удаляются journal del <id>. По дефолту игрок открывает журнал командой /journal. Можно повесить открытие на правый клик книги в инвентаре через config.yml:
journal:
give_on_join: true
custom_journal: true
show_in_backpack: true
Для сводного UI с прогрессом квестов есть встроенное меню (/q menu) или внешние плагины вроде QuestsGUI. Большие проекты обычно пишут собственный GUI поверх PlaceholderAPI, потому что встроенное меню по фиче-листу базовое.
Шпаргалка по основным objectives
| Тип | Что считает | Пример instruction |
|---|---|---|
mobkill | убийство мобов | mobkill ZOMBIE 10 notify |
location | приход в радиус | location 100;64;-50;world 5 |
block | break/place блока | block COAL_ORE 32 events:done |
craft | крафт предмета | craft DIAMOND_PICKAXE 1 |
interact | клик по блоку/мобу | interact left ANY ENTITY |
consume | съесть/выпить | consume cooked_beef 5 |
enchant | зачаровать | enchant diamond_sword sharpness:3 |
fish | рыбалка | fish COD 20 |
kill | убийство игрока | kill name:Steve 1 |
breed | разведение животных | breed COW 3 |
command | ввод команды | command !/spawn |
delay | пройти Х минут | delay 30 ticks:false |
experience | набрать опыт | experience 30 level |
password | ввести в чат | password secretWord |
Полный список и параметры есть на docs.betonquest.org/objectives. Каждый objective можно дополнить флагами notify, persistent (не сбрасывать после reconnect), events: для срабатывания на готовности.
Миграция с 1.x на 2.x: что важно знать
Если у вас на проде ещё 1.x, прыгать на 2.x просто так не получится. Формат пакетов изменился, многие события переименованы, журнал переписан под новый storage. Команда BetonQuest сделала встроенный мигратор:
/q migrate
Команда конвертирует папки QuestPackages/<name>/main.yml старого формата в директории нового. Перед запуском сделайте бэкап plugins/BetonQuest/ и базы (SQLite файл или дамп MySQL). После миграции прогоните сервер на тестовом окружении - часть кастомных событий и интеграций придётся править руками.
Что переименовалось:
tag:-> явный типtagсinstruction- inline-conditions через запятую -> поле
conditions:отдельно - старый формат
point-> новый eventpointсinstruction - compat с Heroes/MythicLib пересобран под новые API
Если миграция падает - откатывайтесь к бэкапу и читайте docs.betonquest.org/migration пошагово. Авторы пишут гайд по каждому breaking-change.
Производительность: что может съесть TPS
BetonQuest сам по себе лёгкий: события и условия отрабатывают на эвентах Bukkit, проверки идут в основном потоке. Узкие места появляются от неправильной конфигурации.
- MySQL вместо SQLite на проде с 100+ онлайн обязателен. SQLite-файл блокируется при записи, и квестовые ивенты выстраиваются в очередь
- objective
locationпроверяет позицию каждого игрока каждую секунду. Если у вас 200 таких objectives на квест, при 100 онлайн это 20000 проверок/сек. Используйтеlocationдля финальных точек, для зон лучшеregionчерез WorldGuard и условиеworldguard - objective
delayработает на тиках только если поставитьticks:true. По умолчанию он использует системное время, что переживает рестарт сервера и не грузит scheduler - debug в config.yml в проде должен быть
false. НаtrueBetonQuest спамит в консоль каждое действие, и при активном квестовом сюжете лог растёт на 100 МБ/час - Conversations с большим деревом (100+ нод) парсятся при
/q reloadсекунды. Разбивайте по файлам внутриconversations/, плагин подхватывает всё
Если плагин начинает лагать в spark profiler - смотрите на тикеры WorldGuard и сами objectives. Часто причина не в BetonQuest, а в callback-плагинах вроде MythicMobs или Citizens, которые BetonQuest зовёт.
Типичные ошибки админов
- Все квесты в одном пакете. Через полгода в
default/копится 200 файлов и любая правка ломает соседний квест. Делайте по пакету на сюжетную линию - Tags вместо objective conditions. Если можно проверить objective напрямую (
condition objective hunt_rats), не плодите промежуточные теги вродеstarted_hunt_rats - Хардкод координат в YAML. Когда переносите спавн - все объекты
locationломаются. Выносите координаты вvariables:пакета и используйте%spawn_x% - Нет journal-записей. Игрок прошёл через 5 NPC, забыл, к кому возвращаться, бросил квест. Каждое значимое действие должно дописывать строку в журнал
- Конфликт ID между пакетами. ID диалога
startесть у трёх пакетов - BetonQuest подхватит первый загруженный. Префиксуйте:city_innkeeper,dungeon_innkeeper - Условия без
!-инверсий. Без!quest_doneNPC будет бесконечно предлагать квест уже выполнившему его игроку - MySQL без бэкапа. Прогресс квестов - это данные игроков, теряются они так же больно, как инвентарь. Настройте дамп раз в час на отдельный диск
FAQ
Можно ли ставить BetonQuest на Folia? Официальной поддержки Folia нет. Часть функций работает, но conversations и таймеры ломаются на регионах. Команда плагина в issues пишет, что Folia в roadmap, но дата не зафиксирована. На Folia пока живите с Quests Plugin или ждите.
Чем BetonQuest отличается от Quests Plugin? Quests проще для входа: GUI-конфигуратор, простые задачи. BetonQuest сложнее, но даёт ветвящиеся диалоги, условия любой логики и реальный квестовый граф. Если нужны "убей 50 зомби - получи алмаз" - Quests хватит. Если нужна Skyrim-like цепочка из 30 NPC и условий - только BetonQuest.
Как сделать ежедневные квесты?
Через event delay с ticks:false и условие objective. Игрок завершает квест -> событие добавляет тег с TTL через delay-objective -> через 24 часа BetonQuest сам снимает тег и квест становится доступен снова.
Что делать, если плагин падает при старте?
В 90% случаев это сломанный YAML в одном из пакетов. Открывайте logs/latest.log, BetonQuest пишет полный путь до проблемной строки. Часто помогает прогон файла через yamllint.
Можно ли импортировать готовые квесты?
Да, на github.com/BetonQuest/Quest-Tutorials лежит коллекция примеров под 2.x. Просто кладёте папку в QuestPackages/ и делаете /q reload. Перед использованием проверяйте версию совместимости - старые пакеты под 1.x не загрузятся без миграции.
Как разделить квесты по серверам в BungeeCord?
В config.yml укажите mysql: с одной БД для всех серверов. BetonQuest хранит теги привязанными к UUID игрока, так что прогресс будет общим. Пакеты при этом разные на каждом сервере: на хабе один набор, в RPG-мире другой.
Если квесты у вас раскручиваются и сервер начинает собирать аудиторию, помните про защиту от DDoS-атак на старте крупных эвентов: один правильный quest-event с массовым телепортом уже несколько раз в нашей практике совпадал с попытками снять сервер. BetonQuest сам по себе на это не повлияет, но иметь фильтр на входе в такие моменты стоит держать в голове.
Protege tu servidor contra ataques DDoS
Protección gratuita con configuración en 5 minutos. 1 TB de tráfico incluido.
Probar gratisArtículos relacionados
Null-атаки и BungeeCord эксплойты: как защитить Minecraft сервер
Null-атаки и эксплойты BungeeCord - одни из самых неприятных проблем для администраторов Minecraft серверов.
Как настроить свой домен для Minecraft сервера
Подробное руководство по подключению собственного домена к Minecraft серверу: DNS-записи, SRV-записи, интеграция с защитой MineGuard и типичные ошибки.