Puzzle
Обзор
Puzzle превращает место в вашем мире в разгадываемую головоломку. Вы выбираете одну из девяти механик: толкать блоки в отверстия, повторять последовательность, переключать рычаги по порядку, перенаправлять лазерные лучи и другие. Каждая головоломка — это запись-аудитория, которую вы размещаете в веб-панели. Она сообщает о результате остальной части TypeWriter через триггеры (onStart, onComplete, onFail, onTimeout, onLifespanExpire) и необязательный факт.
Большая часть поля рисуется на стороне клиента: блоки, подсветка, превью и частицы лазера — это пакеты, отправляемые игроку, который решает головоломку, поэтому двое игроков могут работать над одним полем, не видя прогресса друг друга. Некоторые механики всё же затрагивают мир: головоломка с рамкой для предмета поворачивает настоящую рамку, а головоломка с узором ставит настоящие блоки, если не включён ghostBlocks.
Головоломка принадлежит месту, где вы её построили. Она работает только для игрока, который находится в мире её позиций, в пределах activationRadius блоков от одной из них. Когда игрок добирается до поля, начинается сессия; когда уходит, она завершается и клиентское поле очищается.
Возможности
- Девять типов головоломок — толкание блоков, последовательность на память, лазерная сетка, порядок рычагов, размещение узора, кооперативные нажимные плиты, рамка для предмета, кодовый замок и подношение на пьедестал.
- Общий жизненный цикл — у каждой головоломки есть лимит времени, максимум неверных попыток, перезарядка после неудачи, срок жизни, подсказки и сообщение о завершении.
- Триггеры везде — старт, завершение, провал, тайм-аут и истечение срока жизни могут запускать запись TypeWriter.
- Награда в виде факта — факт увеличивается на
amount, когда головоломка решена. - Цепочки головоломок — запускайте несколько головоломок по порядку и реагируйте на всю цепочку.
- Пространственные ограничения — проверка мира и радиус активации не дают полю появиться в другом измерении или далеко от места.
- Статистика — попытки, решения и лучшее время для каждого игрока, с командой таблицы лидеров.
- Факты состояния — узнавайте, решена ли головоломка или активна для игрока.
- Совместимость с Folia — доступ к миру выполняется в регионе, которому принадлежит головоломка.
Установка
- Установите официальное расширение TypeWriter
Basic, которое предоставляет общие типы, используемые головоломками (звуки, предметы, переменные). - Поместите JAR-файл Puzzle в
plugins/Typewriter/extensions/и перезапустите сервер. - По желанию: добавьте на свои страницы запись Puzzle Artifact, если хотите сохранять попытки, решения и лучшее время (см. предупреждение в разделе «Конфигурация»).
Начало работы
Постройте головоломку с тремя рычагами и дверью:
- В веб-панели TypeWriter откройте страницу manifest и добавьте запись Lever Order.
- В
leversдобавьте три рычага. Для каждого захватите в игреpositionблока рычага и задайтеorderIndexравным0,1и2: в таком порядке игрок должен их переключить. - Задайте
amountравным3, чтобы подсказка выглядела как1/3,2/3,3/3. ВключитеresetOnWrongи задайтеcooldownOnFailравным5, если хотите паузу после ошибки. - Свяжите
onCompleteс последовательностью, которая открывает дверь, аfact— с кэшируемым фактом, хранящим награду. Этот факт также является надёжным способом запомнить, что головоломка решена. - По желанию поместите головоломку под фильтр аудитории, например аудиторию квеста, чтобы она работала только для нужных игроков.
- Опубликуйте, перезапустите или перезагрузите расширение и подойдите к рычагам. Переключение их в правильном порядке решает головоломку. Переключение неверного рычага сбрасывает состояния рычагов и вызывает
onFail.
Записи головоломок регистрируются при загрузке расширения. После добавления головоломки перезагрузите TypeWriter или перезапустите сервер, прежде чем использовать /typewriter puzzle start.
Как это работает
Сессии. Сессия начинается, когда игрок входит в радиус. Она очищает прогресс, неверные попытки и перезарядку после неудачи, запускает timeLimit и lifespan и вызывает onStart. Поэтому maxAttempts — это бюджет на сессию: игрок, у которого попытки закончились, может уйти и вернуться. Головоломка, уже решённая игроком, для него больше не открывается.
Решённая головоломка становится неактивной. Когда игрок решил Block Push, Combination Lock, Lever Order или Laser Grid, она больше не рисует для него поле и не отменяет его действия, даже если он снова попал в её аудиторию (мигающий фильтр, повторный вход). Рычаги и кнопки решённой головоломки работают как обычные блоки, а решённый Pedestal больше не поглощает подбор своего предмета.
Отменённые клики. Сервер отвечает на отменённый клик реальным состоянием блока, по которому кликнули, из-за чего блок, нарисованный на клиенте, исчез бы. Поэтому поле перерисовывается через один тик после каждого отменённого клика (кнопки Memory, сетка Pattern, отклонённые размещения, отклонённые толчки), а также когда игрок бьёт левой кнопкой по нарисованному зеркалу или рычагу.
Завершение срабатывает один раз. Запись факта, сообщение о завершении, onComplete и продвижение цепочки происходят из одного принятого результата, поэтому повторный клик не может вызвать их дважды.
Прогресс. Каждый верный шаг увеличивает прогресс на единицу, вплоть до amount. {progress} и {total} в hintMessage показывают прогресс и amount. Головоломки не задают amount исходя из собственного размера, поэтому вводите реальное число шагов сами.
Общие параметры
Эти поля есть у каждой головоломки.
| Поле | Значение |
|---|---|
fact | Кэшируемый факт, увеличиваемый на amount, когда головоломка решена. |
amount | Максимальный прогресс и награда, добавляемая к факту. |
timeLimit | Секунды до тайм-аута головоломки. 0 отключает его. |
cooldownOnFail | Секунды, которые игрок должен подождать после неудачи. |
maxAttempts | Допустимое число неверных попыток за сессию. 0 отключает ограничение. |
resetOnWrong | Сбрасывает ли неверный шаг прогресс. |
showHints, hintMessage | Подсказка в чате после каждого шага, с {progress} и {total}. Пустое значение ничего не отправляет. |
completionMessage | Отправляется один раз, когда головоломка решена. Пустое значение отключает его. По умолчанию <green>Puzzle completed!. |
onStart, onComplete, onFail, onTimeout, onLifespanExpire | Записи, запускаемые для игрока. |
lifespan | Секунды до истечения головоломки для игрока, что бы он ни делал. 0 отключает его. |
activationRadius | Блоки вокруг позиций головоломки. 0 убирает проверку расстояния, но проверка мира действует всегда. По умолчанию 16. |
criteria | Условия, которым должен соответствовать игрок, чтобы участвовать в головоломке. |
Общие головоломки
Когда isShared включён и у fact головоломки есть группа (пати, команда), группа играет в одну головоломку: каждый шаг, ошибка и перезарядка игрока копируются игрокам этой группы, находящимся в сети. Первый участник, решивший её, решает её для всей группы: fact увеличивается на amount один раз, а каждый участник один раз получает сообщение о завершении, onComplete и шаг цепочки. Отсутствовавший участник получает их по возвращении. Игрок получает завершение головоломки не более одного раза, даже если он сменит группу; только сброс администратором, который его касается, позволяет получить его снова.
- Решение хранится по группам. Смерть или повторное подключение его не сбрасывают и ничего не награждают заново, в отличие от одиночной головоломки, которую можно пройти снова после смерти или отключения.
- Статистика и игровое поле каждого игрока остаются личными. Без группы у
fact, а также для игрока, не состоящего ни в какой группе, ничего не разделяется. Coop Pressure игнорируетisShared: он и так завершает головоломку для каждого участника. - Чтобы пройти её снова, используйте
/typewriter puzzle admin reset <player> <id>: она снова откроется для всей группы этого игрока.
Решение группы сохраняется в Puzzle Artifact. Без него запись существует только в памяти: после перезапуска сервера группа сможет решить головоломку снова и получить награду снова. Добавьте артефакт до использования isShared. Возврат к более старой сборке расширения тоже теряет общую запись, потому что эта сборка сохраняет артефакт без неё, и награды выплачиваются снова. Решение записывается при следующем сохранении (каждые 30 секунд): сбой в этом промежутке может его потерять.
Типы головоломок
| Запись | Что делает игрок | Основные поля |
|---|---|---|
| Block Push | Кликает левой или правой кнопкой по блоку, чтобы толкнуть его на один блок в направлении взгляда игрока, пока каждое целевое отверстие не будет заполнено. | pushBlocks, targetHoles (с acceptedMaterial), blockMaterial, holeMaterial. Число блоков должно равняться числу отверстий. allowPull не действует (вытягивание пока не реализовано). |
| Memory Sequence | Смотрит, как загораются кнопки, затем нажимает их в том же порядке. Последовательность случайна для каждой сессии. | buttons (минимум 2), sequenceLength, highlightDuration, stepGap, inputDelay (тики), highlightMaterial. |
| Laser Grid | Кликает правой кнопкой по зеркалам, поворачивая их, пока каждый приёмник не будет задет лучом своего цвета. | emitters (цвет, направление), mirrors (rotatable, initialDirection), receivers (requiredColor), maxReflections, maxBeamLength, beamDensity. |
| Lever Order | Кликает правой кнопкой по рычагам в порядке их orderIndex. Неверный рычаг сбрасывает все. | levers (position, orderIndex). |
| Pattern Placement | Ставит блоки на сетку, воспроизводя узор. | pattern, gridOrigin, columns, previewOffsetY, ghostBlocks, tolerance. |
| Coop Pressure | Несколько игроков встают на разные плиты и удерживают их несколько секунд. | plates, requiredPlayers, holdDuration (секунды). |
| Item Frame | Кладёт предмет в существующую рамку, затем поворачивает её до целевого угла. | frameTargets (correctRotation от 0 до 7, requiredItem), checkItem. |
| Combination Lock | Нажимает блоки-цифры в порядке кода. | digits (позиции), code (индексы цифр, отсчёт с 0). |
| Pedestal | Кликает правой кнопкой по блоку пьедестала с предметом в руке либо выбрасывает или подбирает предмет рядом с ним. | targetPosition, requiredItem, consumeItem, pickupRadius, consumeDroppedItem. |
Подробности по каждому типу:
- Laser Grid. Луч начинается в одном блоке от излучателя и идёт прямо. Зеркало направляет его в ту сторону, куда оно смотрит. Клик правой кнопкой по зеркалу задаёт его направление противоположным той грани, по которой вы кликнули, либо поворачивает его по часовой стрелке, если вы кликаете по верхней или нижней грани. Сплошной блок останавливает луч. Головоломка решена, когда каждый приёмник задет лучом своего
requiredColor. Лучи отображаются частицами. Зеркало не исчезает при правом клике: поле перерисовывается после клика. Лучи рисуются через центр блоков и поворачивают точно на каждом зеркале;beamDensity— число частиц на блок. Длина луча не большеmaxBeamLengthблоков (по умолчанию 64; 0 или меньше означает 64, никогда не безлимитно), и он никогда не загружает чанк: он останавливается на краю загруженного мира. Поле с более длинным лучом должно увеличитьmaxBeamLength. - Block Push. Каждый толчок сдвигает блок на одну клетку в направлении взгляда игрока. Блок, возвращённый на свою стартовую клетку, всегда принимается там, а целевая лунка рисуется заново, когда блок был протолкнут через неё и дальше. Оставляйте стартовые клетки в мире пустыми (воздух). Настоящий блок там скрыт на клиенте, но остаётся твёрдым для сервера, так что никто не сможет на нём стоять. Отклонённый толчок (стена, другой блок) засчитывается как одна ошибка на блок и целевую клетку до тех пор, пока толчок не удастся, поэтому удержание клика у стены не расходует
maxAttempts. - Lever Order. Рычаг находится в том состоянии, в котором он находится в мире, когда игрок подходит к полю, переключается оттуда и возвращается в него при сбросе или после неверного порядка, даже если он покоится включённым. Клик во время паузы после ошибки не доходит до настоящего рычага.
- Combination Lock. Нумерация начинается с 0: первая позиция в
digits— цифра 0, вторая — цифра 1 и так далее.codeперечисляет эти индексы в порядке нажатия. Например, при четырёх кнопках вdigitsкод[2, 0, 3]означает: третья кнопка, первая кнопка, четвёртая кнопка. Значениеcodeвне диапазона цифр заставляет замок игнорировать все нажатия; журнал сервера называет это значение. - Pattern Placement.
patternперечисляет материалы построчно, ширинойcolumns, и его длина должна быть кратнаcolumns. Сетка лежит в горизонтальной плоскости на высоте Y уgridOrigin, столбцы идут вдоль X, а строки вдоль Z. Превью парит наpreviewOffsetYблоков выше. При включённомghostBlocksполупрозрачная версия рисуется прямо на сетке, а верные блоки показываются на стороне клиента, при этом предмет забирается у игрока. Неверное размещение всегда отменяется.tolerance— это число неверных размещений, допустимых до сброса прогресса. - Coop Pressure. Плита засчитывается, когда ноги игрока стоят на этом блоке или на блоке над ней. По одному игроку на плиту. В головоломке участвуют все игроки аудитории, поэтому добавляйте их командой
/typewriter puzzle join <entry id>. Когда плиты удерживались в течениеholdDuration, каждый участник завершает головоломку. - Item Frame. Рамка уже должна существовать в заданной позиции; головоломка никогда её не создаёт. Пустая рамка принимает только
requiredItem, берущийся из руки игрока. Каждый клик по заполненной рамке поворачивает её на один шаг (45 градусов), аcorrectRotation— это число шагов от 0 до 7, при котором положение верное. Рамка — это настоящая сущность, поэтому поворот виден всем. - Pedestal.
requiredItemможно отдать правым кликом или выбросить в пределахpickupRadiusблоков от пьедестала. Выброшенный подходящий предмет удаляется, если включёнconsumeDroppedItem.
Команды
Все команды — это подкоманды /typewriter (псевдоним /tw). <id> — идентификатор записи головоломки. Право требуется только для команд admin.
| Команда | Описание |
|---|---|
/typewriter puzzle | Открыть чат-меню первой записи Puzzle Menu или сообщить, что такой нет. |
/typewriter puzzle list | Перечислить зарегистрированные головоломки и их типы. |
/typewriter puzzle start <id> | Добавить себя в аудиторию головоломки. Отказывает, если вы её уже решили. |
/typewriter puzzle join <id> | Присоединиться к уже запущенной головоломке, например кооперативной. |
/typewriter puzzle chain <id> | Запустить цепочку головоломок по идентификатору записи или названию. |
/typewriter puzzle status | Показать ваше состояние по каждой головоломке: активна, завершена, остановлена или неактивна. |
/typewriter puzzle leaderboard <id> | Показать вашу статистику и десятку лучших игроков по головоломке. |
/typewriter puzzle stop [id] | Остановить одну головоломку или все ваши активные головоломки и сбросить их прогресс. |
/typewriter puzzle close | Закрыть ваш открытый инвентарь. |
/typewriter puzzle admin reset <player> <id> | Сбросить состояние игрока для головоломки и перезапустить её. Для общей головоломки открывает её заново для всей группы игрока. |
/typewriter puzzle admin reload | Очистить все состояния выполнения и цепочки. |
Права
| Право | Что даёт |
|---|---|
puzzle.admin | Команды /typewriter puzzle admin. |
Конфигурация
Сохранение данных. Без Puzzle Artifact ничего не сохраняется. С ним расширение сохраняет состояние и статистику каждые 30 секунд и при выключении, а при запуске загружает их. Создайте ровно один артефакт и сохраните его сгенерированный artifactId. Артефакт обязателен для общих головоломок (см. Общие головоломки).
Когда игрок отключается, состояние его головоломки удаляется из памяти, и следующее сохранение его не содержит. Статистика остаётся. Чтобы навсегда запомнить решённую головоломку, задайте fact головоломки и считывайте этот факт в своих критериях. Puzzle Solved Fact отражает только состояние в памяти. Общая головоломка — исключение: её решение принадлежит группе и сохраняется в артефакте.
Сообщения. Ни один текст, показываемый в игре, не зашит в код. Тексты конкретной головоломки — это поля её записи, а ответы команд и два сообщения, общие для всех головоломок, — сниппеты. См. Редактируемые тексты.
Редактируемые тексты
Тексты написаны в MiniMessage, поэтому их можно переформулировать, перевести или перекрасить. {name} в тексте заменяется значением, указанным в таблицах ниже; несуществующий плейсхолдер остаётся как написан. Плейсхолдеры PlaceholderAPI (%...%) читаются для игрока, который получает текст. Неизменным, на английском, остаётся только журнал консоли сервера.
Поля записей
Эти поля находятся в записи, в веб-панели. Каждое из них — текст для каждого игрока, поэтому поддерживает переменные, а пустое значение ничего не отправляет. Существующие страницы сохраняют уже записанные тексты; значения по умолчанию ниже применяются к новым записям и к страницам, которые никогда не сохраняли это поле.
| Запись | Поле | По умолчанию | Плейсхолдеры |
|---|---|---|---|
| Любая головоломка | hintMessage | Подсказка каждого типа головоломки, например <yellow>Repeat the sequence! {progress}/{total}. | {progress}, {total} |
| Любая головоломка | completionMessage | <green>Puzzle completed! | нет |
| Puzzle Menu | titleText | <gold><bold>Puzzles</bold> <gray>- | нет |
| Puzzle Menu | puzzleLineText | <green>{puzzle} <gray>- <aqua>click to start | {puzzle} — идентификатор записи головоломки |
| Puzzle Menu | footerText | <gray>Use <white>/typewriter puzzle stop<gray> to stop all active puzzles. | нет |
| Memory Sequence | memorizeMessage | <gold>Memorize the sequence… | нет |
| Memory Sequence | yourTurnMessage | <green>Your turn! <white>{progress}/{total} | {progress}, {total} |
| Memory Sequence | stepCorrectMessage | <green>Well done! <white>{progress}/{total} | {progress}, {total} |
| Lever Order | wrongOrderMessage | <red>Wrong order — the levers have been reset. | нет |
| Pattern Placement | progressMessage | <green>Pattern <white>{progress}/{total} | {progress}, {total} |
| Item Frame | missingFrameMessage | <red>No item frame at <white>{x} {y} {z} | {x}, {y}, {z} |
| Item Frame | wrongItemMessage | <red>That is not the right item in the frame. | нет |
| Item Frame | insertingMessage | <gray>Inserting the item… | нет |
| Item Frame | missingItemMessage | <yellow>First place the requested item in the frame. | нет |
| Item Frame | itemPlacedMessage | <green>Item placed — rotate the frame. | нет |
| Item Frame | rotationMessage | <gray>Rotation {current}/{total} | {current}, {total} |
hintMessage, completionMessage и поля чат-меню отправляются в чат; остальные поля показываются в action bar. Некоторые из этих значений по умолчанию в прежних сборках были на французском; теперь они на английском, а страница, сохранившая французский текст, оставляет его.
Сниппеты
Всё, что выводят команды /typewriter puzzle, включая административные, и два сообщения, общие для всех головоломок, — это сниппеты TypeWriter. Откройте plugins/Typewriter/snippets.yml, найдите ключ в content.puzzle, измените значение и выполните /tw reload. Расширение регистрирует все свои сниппеты с текстом по умолчанию при запуске, поэтому после первого запуска они появляются в файле.
Сниппет (в content.puzzle.) | По умолчанию | Плейсхолдеры |
|---|---|---|
command.no_menu | <red>No puzzle menu configured. | нет |
command.list.none | <red>No puzzles configured. | нет |
command.list.header | <gold>=== Available Puzzles === | нет |
command.list.line | <green>{puzzle} <gray>- {type} | {puzzle}, {type} |
command.puzzle_not_found | <red>Puzzle not found: <white>{puzzle} | {puzzle} |
command.start.already_completed | <yellow>Puzzle already completed. Use <white>/typewriter puzzle admin reset {player} {puzzle}<yellow> to replay it. | {player}, {puzzle} |
command.start.started | <green>Starting puzzle: <white>{type} | {type} |
command.join.already_completed | <yellow>Puzzle already completed for you: <white>{puzzle} | {puzzle} |
command.join.joined | <green>Joined puzzle: <white>{type} | {type} |
command.stop.not_active | <gray>Puzzle is not active: <white>{puzzle} | {puzzle} |
command.stop.stopped | <yellow>Stopped puzzle: <white>{puzzle} | {puzzle} |
command.stop.all_none | <gray>No active puzzle. | нет |
command.stop.all_stopped | <yellow>Stopped <white>{count} <yellow>puzzle(s). | {count} |
command.status.header | <gold>=== Puzzle Status === | нет |
command.status.line | <gray>{puzzle}: {status} <dark_gray>progress={progress} | {puzzle}, {status}, {progress} |
command.status.active | <green>ACTIVE | нет |
command.status.completed | <aqua>COMPLETED | нет |
command.status.stopped | <yellow>STOPPED | нет |
command.status.inactive | <gray>INACTIVE | нет |
command.chain.not_found | <red>Chain not found: <white>{chain} | {chain} |
command.chain.invalid | <red>Chain is invalid or contains unresolved puzzles: <white>{chain} | {chain} |
command.chain.empty | <red>Chain has no resolvable puzzle entries. | нет |
command.chain.started | <green>Starting puzzle chain: <white>{chain} | {chain} |
command.leaderboard.header | <gold>=== Puzzle Stats: <white>{puzzle} <gold>=== | {puzzle} |
command.leaderboard.attempts | <gray>Attempts: <white>{attempts} | {attempts} |
command.leaderboard.solves | <gray>Solves: <white>{solves} | {solves} |
command.leaderboard.best_time | <gray>Best time: <white>{seconds}s | {seconds} |
command.leaderboard.rows_header | <gold>--- Leaderboard --- | нет |
command.leaderboard.row | <gray>#{rank} <white>{player} <gray>- <white>{solves} solves | {rank}, {player}, {solves} |
command.leaderboard.row_timed | <gray>#{rank} <white>{player} <gray>- <white>{solves} solves <gray>{seconds}s | {rank}, {player}, {solves}, {seconds} |
command.admin.reset.player_not_found | <red>Player not found: <white>{player} | {player} |
command.admin.reset.done | <green>Reset puzzle <white>{puzzle} <green>for <white>{player} | {puzzle}, {player} |
command.admin.reset.done_group | <green>Reset puzzle <white>{puzzle} <green>for <white>{player} <green>and its group (<white>{count}<green> online) | {puzzle}, {player}, {count} |
command.admin.reload.done | <green>Puzzle runtime states cleared. | нет |
play.cooldown_wait | <red>Puzzle on cooldown — <white>{seconds}s | {seconds} |
play.max_attempts | <red>Too many mistakes — restart the puzzle to try again. | нет |
{type} — название типа головоломки (Memory Sequence, Lever Order, ...), а {status} — один из четырёх сниппетов command.status.*, поэтому оба сохраняют свои цвета. Любой другой плейсхолдер — обычный текст: то, что игрок вводит в команде, не может добавить форматирование в ответ.
Записи
Записей: 14, сгенерированы из исходного кода расширения.
Действия1
- Puzzle MenuPuzzle Menu
Факты2
- Puzzle Active FactPuzzle Active Fact
- Puzzle Solved FactPuzzle Solved Fact
Аудитории9
- Puzzle Block PushPush blocks into target holes -
- Puzzle Combination LockEnter the correct code by pressing buttons/levers in sequence
- Puzzle Coop PressureCooperative pressure plate puzzle -
- Puzzle Item FrameRotate item frames to the correct angles
- Puzzle Laser GridLaser grid puzzle -
- Puzzle Lever OrderPuzzle where levers must be activated in the correct order
- Puzzle MemoryMemory sequence puzzle -
- Puzzle PatternPattern placement puzzle -
- Puzzle PedestalOffer an item on a pedestal to solve the puzzle
Артефакты1
- Puzzle ArtifactPersists puzzle states across server restarts
Другие записи1
- Puzzle ChainChain of puzzles -
Устранение неполадок
Поле не появляется. Вы должны находиться в мире позиций головоломки и в пределах activationRadius от одной из них. Позиции, оставленные равными 0, 0, 0, игнорируются, поэтому у головоломки без заданных позиций нет точки привязки.
При клике ничего не происходит. Проверьте, что вы в аудитории (критерии должны выполняться, а фильтр аудитории должен включать вас) и что головоломка ещё не решена для вас: используйте /typewriter puzzle status, а чтобы сыграть заново, /typewriter puzzle admin reset <player> <id>. Клики во время перезарядки после неудачи игнорируются; в экшн-баре показано оставшееся время.
/typewriter puzzle start сообщает, что головоломка не найдена. Головоломки регистрируются при загрузке расширения по идентификатору записи. Перезагрузите после добавления головоломки и используйте идентификатор записи, а не её название.
Головоломка на память никогда не запускается. В buttons нужно как минимум 2 элемента, и у каждого должна быть позиция.
Головоломка с узором игнорирует мои блоки. Длина pattern должна быть кратна columns, а блоки нужно ставить на сетку на высоте Y у gridOrigin. Неверный материал отменяется.
Головоломка с рамкой сообщает, что рамки нет. Сначала поставьте рамку для предмета в заданной позиции. В логе также выводится предупреждение с координатами.
Прогресс теряется после повторного подключения. См. предупреждение в разделе «Конфигурация»: используйте fact, чтобы сохранить результат.
Кооперативная головоломка никогда не завершается. Каждый игрок должен быть в аудитории (/typewriter puzzle join <id>), стоять на отдельной плите и оставаться на ней в течение holdDuration. Предметы, выброшенные на плиты, не считаются.