Генерируемые подземелья
У генерируемого подземелья нет шаблонного мира. Вы один раз строите небольшие комнаты, описываете, как они соединяются, а генератор собирает новую планировку для каждого забега: от стартовой комнаты через обычные, сокровищные и секретные комнаты до комнаты босса.
Фиксированные и генерируемые подземелья используют одни и те же забеги, меню, сундуки, NPC, мобов, события и факты. Меняется только то, откуда берутся комнаты.
Составные части
| Часть | Запись | Что это |
|---|---|---|
| Вид двери | Dungeon Connector Type | Размер проёма двери, блок, закрывающий неиспользуемую дверь, и какие виды можно соединять. |
| Комната | Dungeon Room Template | Сохранённая постройка (структура Paper .nbt, хранящаяся как артефакт) с её категорией, дверями и маркерами. |
| Пул | Dungeon Room Pool | Взвешенный список шаблонов комнат. |
| Генератор | Dungeon Generator | Правила: какие пулы, сколько комнат, как глубоко находится босс, как часто путь ветвится. |
| Аффикс | Dungeon Affix | Случайно выбираемый модификатор забега, например «быстрые мобы». |
| Подземелье | Dungeon Instance | Его поле generator превращает его в генерируемое подземелье. |
Постройте одно по шагам
- Виды дверей. Добавьте хотя бы один Dungeon Connector Type. Задайте
widthиheight(по умолчанию 3 на 3),sealBlock, закрывающий неиспользуемую дверь (по умолчаниюminecraft:stone_bricks), и, если видов несколько,compatibleWith. Вид всегда можно соединить с самим собой. - Комнаты. Для каждой комнаты добавьте Dungeon Room Template и используйте игровой редактор, чтобы захватить её блоки и расставить двери и маркеры. Выберите её
category. - Пулы. Добавьте Dungeon Room Pool для стартовых комнат, один для комнат босса, один (или несколько) для остальных комнат и, по желанию, один для коридоров. Пул стартовых комнат, комнат босса или коридоров содержит шаблоны только этой категории. Обычный пул может смешивать шаблоны
NORMAL,TREASUREиSECRET. - Генератор. Добавьте Dungeon Generator и задайте
startPool,bossPool, при желанииcorridorPoolиnormalPoolsс весом у каждого. - Подземелье. В вашем Dungeon Instance задайте
generator. ОставьтеtemplateWorldпустым: у генерируемого подземелья нет шаблонного мира. Изоляция должна бытьAUTOилиWORLD_PER_RUN. - Игровая логика. Используйте триггеры
onEnterиonClearшаблонов комнат, маркеры TRIGGER, события комнат, записи Dungeon Mob Spawn на маркерах MOB и завершайте забег с помощью Dungeon Complete.
Если пулы и шаблоны не могут составить подземелье, запуск отклоняется, а лог сервера объясняет почему (например, пул без стартовой комнаты или шаблон без читаемого захвата). Поле messages генератора хранит причины, о которых сообщается вам, автору. Игрок видит только короткий текст из сниппетов content.dungeon_generated.refusal.setup (пулы и шаблоны не могут составить подземелье) и content.dungeon_generated.refusal.paste (комнаты не удалось вставить), которые можно редактировать в веб-панели. Ничего при этом не списывается. Строка, объявляющая аффиксы забега, — это сниппет content.dungeon_generated.affix.announcement.
Категории комнат
category шаблона комнаты указывает, какую роль он может играть.
| Категория | Роль |
|---|---|
START | Здесь начинается забег. Одна на подземелье. Должна содержать маркер SPAWN. |
NORMAL | Обычная комната. |
TREASURE | Всегда на ответвлении, никогда на пути к боссу. |
CORRIDOR | Вставляется между двумя комнатами, которые не могут соприкасаться напрямую. |
SECRET | Всегда тупик. |
BOSS | Последняя комната. Одна на подземелье. |
Комнаты соединяются дверь к двери, поэтому комната без дверей может быть только тупиковой START. Дверь с включённым required должна быть соединена с другой комнатой: шаблон, который не может заполнить все свои обязательные двери, никогда не используется. Дверь, через которую никто не прошёл, закрывается sealBlock её вида.
Маркеры
Маркер — это точка интереса внутри комнаты. У каждого есть kind:
| Вид | Что делает | Поле для заполнения |
|---|---|---|
SPAWN | Где появляются игроки при начале забега. Используется только первый SPAWN стартовой комнаты. | нет |
CHEST | Здесь ставится сундук с добычей. Его позиция и yaw заменяют расположение записи. Сундук, названный маркером, ставится всегда, даже если его запись в manualMode. | chest: Dungeon Loot Chest |
TRIGGER | Триггеры срабатывают для игрока, достигшего комнаты. | triggers |
NPC | Здесь стоит Dungeon NPC Instance, видимый участникам забега. | npc |
MOB | Dungeon Mob Spawn вызывает здесь своих мобов при первом входе участника забега в комнату. | mob |
Yaw маркера поворачивает сундук (он смотрит в сторону, противоположную yaw) и NPC (он смотрит в сторону yaw). Маркер связывается со своей записью по его месту в списке markers.
Комнаты в игре
Когда игрок входит в комнату генерируемого подземелья, срабатывают триггеры onEnter её шаблона, затем триггеры её маркеров TRIGGER и мобы её маркеров MOB. При включённом enterOnce (по умолчанию для шаблонов) они срабатывают только при первом входе каждого игрока в комнату за забег.
Триггеры onClear срабатывают один раз за забег, когда выполняется действие Dungeon Clear Room, пока игрок стоит в комнате. Платформа никогда сама не решает, что комната зачищена: решаете вы, например по событию смерти моба, когда умирает последний монстр.
Триггеры комнаты читают эти значения из контекста (через interaction_context_variable):
| Ключ | Значение |
|---|---|
RUN_ID | Id забега. |
SEED | Seed подземелья в десятичной записи. |
ROOM | Номер комнаты: 0 — стартовая комната, далее в порядке, в котором их разместил генератор. |
ROOM_TEMPLATE | Id записи шаблона комнаты. |
DIFFICULTY | difficulty генератора. |
POSITION | Блок маркера для маркера TRIGGER, иначе позиция игрока. |
Триггеры аффикса читают только RUN_ID, SEED и DIFFICULTY. Фиксированное подземелье не предоставляет ни одного из этих ключей.
Seed, аффиксы и сложность
Один и тот же seed всегда даёт одно и то же подземелье, поэтому планировку можно повторить. Для каждого забега выбирается новый seed. Seed сохраняется вместе с забегом, поэтому перезагрузка перестраивает то же подземелье в памяти. Если его не удаётся перестроить, забег закрывается при запуске, а не подхватывается с комнатами, которых никто не знает.
Аффиксы выбираются после планировки из affixes генератора по их weight, affixCount штук без повторов. Выбор следует за seed, но никогда не меняет планировку. Их модификаторы и триггеры применяются к каждому участнику при начале забега.
difficulty — просто число, передаваемое вашим триггерам через контекст: само по себе оно планировку не меняет.
Важные настройки генератора
| Поле | По умолчанию | Примечания |
|---|---|---|
minRooms, maxRooms | 6, 10 | Общее число комнат, включая стартовую и босса, без коридоров. Допустимый диапазон: от 2 до 256. |
minBossDepth | 3 | Босс находится не менее чем на столько шагов от старта. |
branchRatePercent | 40 | Вероятность в процентах того, что комната за пределами основного пути открывает боковое ответвление. |
quotas | нет | Ограничения на число комнат NORMAL, TREASURE и SECRET. Категория без ограничения не ограничена. |
trialBudget, replans | 20000, 5 | Сколько усилий тратит поиск, прежде чем сдаться. Произведение trial budget на (replans + 1) должно укладываться в 5 000 000. |
baseY | 64 | Высота пола стартовой комнаты в мире забега. |
roomsPerTick | 4 | Комнат, вставляемых за тик сервера. Меньше — короче тики; больше — быстрее. |
pasteTimeoutSeconds | 120 | После этого запуск отменяется, стоимость возвращается, а мир удаляется. |
naturalSpawning | выкл. | Монстры и животные появляются сами в мире забега. По умолчанию выключено. |
verticalMargin | 1.0 | Блоков, добавляемых над потолком и под полом каждой комнаты при определении, внутри ли игрок. |
paster | STRUCTURE | Использует API структур Paper: другие плагины не нужны. |
Шаблон комнаты имеет не более 256 блоков по каждой стороне, не более 64 дверей и 1024 маркеров.
Игровой редактор
Откройте Dungeon Room Template в веб-панели и нажмите редактор содержимого поля artifactId. На хотбаре появится набор инструментов:
| Инструмент | Назначение |
|---|---|
| Жезл углов | Левый клик по блоку — угол A, правый клик по блоку — угол B. |
| Захват | Сохраняет блоки области как постройку шаблона. |
| Инструмент двери | Правый клик по блоку стены добавляет дверь (блок — нижний центр проёма). Левый клик удаляет двери там. |
| Тип двери | Правый клик — следующий тип соединителя, левый клик — предыдущий. |
| Переключатель обязательности | Переключает, будут ли следующие двери обязательными. |
| Инструмент маркера | Правый клик по блоку добавляет маркер перед ним. Левый клик удаляет маркеры там. |
| Вид маркера | Правый клик — следующий вид, левый клик — предыдущий. |
| Сохранить | Записывает двери и маркеры в запись. |
Босс-бар показывает размер области, число дверей и маркеров и наличие несохранённой работы. Размер комнаты считывается из сохранённой постройки и никогда не вводится вручную. Прежде чем добавлять дверь, нужно создать и опубликовать хотя бы один тип соединителя.
Захваты по умолчанию пропускают сущности, потому что живая сущность меняет комнату при каждом захвате и появляется как бродячий моб в каждой копии. Эти варианты поведения и все тексты редактора — сниппеты Typewriter в content.dungeon_room_template., поэтому вы можете менять или переводить их в веб-панели:
| Сниппет | По умолчанию | Значение |
|---|---|---|
capture.include_entities | false | Сохраняет ли захват сущности области. |
capture.max_volume | 262144 | Наибольшее число блоков, которое читает один захват. Чтение идёт за один тик сервера: очень большая область удерживает этот тик. |
capture.timeout_seconds | 30 | Секунды ожидания захвата, прежде чем отказаться. |
sound.confirm | entity.experience_orb.pickup | Звук после захвата или сохранения. Пусто: нет. |
Ограничения и хорошая практика
- Генерируемые подземелья используют только
WORLD_PER_RUN: каждый забег создаёт мир и затем удаляет его. - У редактора фиксированных комнат (узлов) свои сниппеты в
content.dungeon_room.(сообщенияnode.*,save.*,editor.*, инструментыtool.add,tool.remove,tool.save). - Стройте комнаты так, чтобы две соединяемые двери одного вида совпадали. У проёма чётной ширины лишний блок находится на большем x или z шаблона. Генератор сдвигает комнату на один блок, когда этого требует проём чётной ширины.
- Всё подземелье должно умещаться между самым нижним и самым верхним блоком мира, считая от
baseY. - Не полагайтесь на фиксированное число комнат: используйте маркеры и события вместо номеров комнат.