Перейти к основному содержимому

GUI

Меню инвентаря, создаваемые в веб-панели: раскладки, предметы, действия по клику, хранилище и таблицы лидеров.

Бесплатныеv0.20Меню и визуал

Обзор​

GUI превращает одну запись TypeWriter, Open GUI, в полноценное меню-инвентарь. Вы выбираете тип контейнера (сундук, наковальня, окно торговли, написанная книга...), пишете заголовок в MiniMessage, а затем описываете содержимое как дерево макетов (layouts), хранящихся в layoutPool записи. Каждый макет размещает предметы: материал, название, описание (lore) и то, что происходит при клике игрока.

Всё редактируется в веб-панели: файлы меню вручную писать не нужно. Меню открывается как любое другое действие: из шага квеста, диалога NPC, события-команды или другого меню. Клики выполняют консольные команды, запускают другие записи и изменяют факты, так что меню — это ещё один способ управлять вашими страницами TypeWriter.

GUI также является основой для других меню-расширений BTC. Shops и Quest Codex не поставляют собственное окно: они размещают маркерные предметы в макете open_gui, а расширение заполняет их товарами или квестами.

Возможности​

  • Десять макетов — simple, flex, paginated, scrollable, frame, composite, book, merchant, storage и leaderboard.
  • 24 типа контейнеров — сундуки от 9 до 54 слотов, а также наковальня, стол зачарований, кузнечный стол, камнерез, точило, ткацкий станок, картографический стол, торговец, книга, воронка, печи и другие.
  • MiniMessage везде — цвета, градиенты и плейсхолдеры PlaceholderAPI в заголовках, названиях предметов и описаниях.
  • Действия для каждого типа клика — левый, правый, с Shift, средний, двойной клик, цифровые клавиши, выброс и обмен с левой рукой, у каждого свои команды и триггеры.
  • Права на слоты — скрывайте слот через viewPermission или оставляйте его видимым, но неактивным через clickPermission.
  • Повторение слотов — заполняйте ряд или блок с помощью count, direction, gap и repeatY, не копируя предметы.
  • Представления и вкладки — одна оболочка меню, несколько экранов, заголовок с навигационной цепочкой и подсвечиваемые вкладки.
  • Постоянное хранилище — слоты, сохраняющие предметы для каждого игрока или группы, с квотами, плейсхолдерами и необязательным выбросом при закрытии.
  • Таблицы лидеров — ранжируйте игроков, миры и группы по одному или нескольким фактам, включая игроков не в сети, либо показывайте строки, которые даёт другое расширение через поле source (например, статистику Dungeon).
  • Расширенный инвентарь — превратите собственный инвентарь игрока в четыре дополнительных ряда меню для холста из десяти рядов.

Установка​

  1. Установите TypeWriter на сервер Paper или Folia. Должен присутствовать PacketEvents, который TypeWriter и так требует.
  2. Скачайте JAR-файл из релизов GitHub GUI (кнопка в сводной панели выше).
  3. Положите его в plugins/Typewriter/extensions/ и перезапустите сервер.
  4. По желанию: установите CraftEngine, если в заголовках используются теги <image> или <shift> для отрисовки пользовательских фонов.

Устанавливайте GUI раньше расширений, которые на него опираются, таких как Shops и Quest Codex.

Веб-редактор

Публичный релиз GUI не включает отдельный редактор меню и его веб-сервер: меню редактируются в веб-панели TypeWriter. В релиз входит только проверка при запуске, которая читает опубликованные записи open_gui и сообщает в консоли о неработающих меню (см. раздел «Устранение неполадок»).

Быстрый старт​

Соберём небольшое меню из трёх кнопок:

  1. В веб-панели откройте страницу sequence и добавьте запись Open GUI. Назовите её main_menu.
  2. Установите guiType в CUSTOM, size в SIZE_27, а title в <gold>Main menu.
  3. В layoutPool добавьте макет типа simple, задайте ему id main, затем впишите main в mainLayoutId.
  4. В items макета добавьте предмет в позиции x 4, y 1. Выберите в item DIAMOND, задайте displayName значение <aqua>Rewards и добавьте в lore строку <gray>Click to claim.
  5. В interactionList добавьте взаимодействие с type LEFT_CLICK. Добавьте в commands консольную команду, например give %player% diamond 1, или свяжите запись в triggers. Включите closeMenu, чтобы закрывать меню после клика.
  6. Добавьте второй предмет simple с count 9, direction right и серой цветной стеклянной панелью, чтобы нарисовать ряд рамки. Задайте его displayName один пробел.
  7. Свяжите запись Open GUI с тем, что её запускает, например с триггером варианта диалога или событием-командой, затем нажмите Publish.
Начинайте с простого

Добейтесь работы одного макета simple в игре, прежде чем добавлять слои frame, scrollable или paginated. Каждый макет адресуется по своему id, поэтому опечатка в mainLayoutId — первое, что стоит проверить, если меню открывается пустым.

Как это работает​

Когда действие срабатывает, расширение строит дерево макетов для этого игрока (условия и права вычисляются именно в этот момент), регистрирует сессию меню и показывает инвентарь. Каждый клик сопоставляется со слотом в этой позиции, после чего выполняется подходящее взаимодействие. Сессия запоминает предыдущие меню, поэтому gui:back возвращает в меню, из которого пришёл игрок.

Меню​

Типы контейнеров​

guiType выбирает окно. CUSTOM — это обычный инвентарь наподобие сундука, высоту которого вы выбираете через size. size применяется только к CUSTOM и по умолчанию равен шести рядам; остальные типы используют ванильный размер своего окна.

guiTypeОкно
CUSTOM, CHEST, ENDER_CHEST, BARREL, SHULKER_BOXСетки в стиле сундука. Для CUSTOM size может быть SIZE_9, SIZE_18, SIZE_27, SIZE_36, SIZE_45 или SIZE_54.
HOPPER, DISPENSER, DROPPERНебольшие контейнеры фиксированного размера.
FURNACE, BLAST_FURNACE, SMOKER, BREWING_STAND, BEACONОкна механизмов.
CRAFTING_TABLE, ENCHANTING_TABLE, ANVIL, SMITHING_TABLE, GRINDSTONE, LOOM, CARTOGRAPHY_TABLE, STONECUTTERВанильные станции. Без макета они ведут себя как ванильный экран; GUI управляет только открытием и закрытием.
MERCHANT, VILLAGER_TRADEОкно торговли с жителем, заполняемое макетом merchant.
BOOKНаписанная книга, заполняемая макетом book.

Макеты​

Каждый макет — это именованная запись layoutPool. Макет, указанный в mainLayoutId, является корневым; к остальным обращаются по ссылкам (дочерние элементы composite, innerId у scrollable, layoutId у frame).

МакетДля чего использоватьКлючевые поля
simpleФиксированные кнопки и декор в позициях x/y.items
flexПредметы, автоматически раскладываемые по рядам.justifyContent (START, CENTER, END, SPACE_BETWEEN), alignItems, wrap, virtualHeight
paginatedДлинный список, разбитый на страницы.itemsPerPage, slots, items, navigationButtons (NEXT, PREVIOUS, BACK, INDICATOR)
scrollableСодержимое выше или шире окна.innerId, virtualWidth, virtualHeight, buttons (direction, step), showDefaultButtons, defaultStep
frameНесколько независимых прямоугольников, например вкладки, содержимое и нижняя часть.frames (id, x, y, width, height, layoutId)
compositeНаложение слоёв: фон, содержимое, кнопки.children (id макетов, более поздние рисуются поверх)
bookСтраницы написанной книги.pages (MiniMessage)
merchantОбмен с жителем с пользовательскими предметами.trades (result, costOne, costTwo, maxUses, criteria)
storageПостоянные слоты на основе артефакта GUI Storage.entry, groupKey, slots
leaderboardСтроки рейтинга со страницами, по фактам или из source другого расширения.leaderboard, x, y, width, height, previousButton, nextButton

Макеты book и merchant работают только как главный макет, при этом guiType переопределяется на соответствующее окно. Макет scrollable получает стрелки по умолчанию, пока включён showDefaultButtons (по умолчанию): по одной для каждого направления без записи в buttons, см. Макеты, фреймы и слоты.

Подробный разбор каждого макета смотрите в разделе Макеты, фреймы и слоты.

Предметы и слоты​

Каждый предмет макета — это описание слота с одинаковым набором полей:

ПолеРоль
itemОтображаемый предмет. Если оставить пустым, слот показывает предмет, который игрок держит в основной руке.
displayName, loreТекст MiniMessage с поддержкой PlaceholderAPI. По умолчанию названия не курсивные; добавьте <italic>, если нужен курсив. Пустой displayName сохраняет название предмета вместо замены его пустым.
x, yСтолбец от 0 до 8 и ряд, где 0 — самый верхний.
rollPerSlotДля предмета, повторяемого в нескольких слотах, у которого item случайный: выключено (по умолчанию) — выбор делается один раз, и все слоты показывают этот результат; включено — каждый слот выбирает сам при открытии меню. Результат сохраняется, пока меню открыто, если не включён liveItem.
liveItemВыключено (по умолчанию): предмет выбирается при открытии меню и сохраняется на всю сессию; при обновлении меняются только название и описание. Включено: предмет вычисляется заново при каждом обновлении, поэтому случайный предмет выбирается каждый раз заново. При включённом rollPerSlot каждый повторяемый слот выбирает сам при каждом обновлении; иначе все повторяемые слоты делят один выбор на обновление. Пустое название по-прежнему игнорируется.
count, direction, gap, repeatYПовторение слотов, см. ниже.
criteriaСлот не отображается для игроков, которые не соответствуют условию.
viewPermissionПраво, необходимое, чтобы видеть слот.
clickPermissionПраво, необходимое для использования слота; без него слот отображается, но неактивен.
allowPickup, isGhostМожно ли забрать предмет из меню. Оба выключены по умолчанию; ghost-предметы можно кликать, но нельзя перемещать или копировать.
cooldownTicksЧисло тиков до следующего клика по тому же слоту.
interactionList, triggers, modifiersЧто делает клик.
inputОткрывает диалог ввода текста при клике.
storageIdПревращает слот в постоянный слот хранилища из storagePool.
buttonType, buttonPrefixПомечает слот как кнопку, предоставляемую другим расширением.
animationПеремещает слот в целевую позицию за заданное число миллисекунд при открытии меню.

Повторение слотов. count повторяет предмет вдоль direction (right, left, down, up). gap — это шаг, а не отступ: 1 означает вплотную, 2 оставляет один пустой слот между копиями, а 0 ведёт себя как 1. repeatY повторяет всю линию по перпендикулярной оси. Без direction поля count, gap и repeatY игнорируются и размещается один слот. Эти поля считают слоты, а не размер стопки предмета.

Перекрытия. Когда два слота занимают одну ячейку, тот, что что-то делает (действие по клику, тег, слот хранилища), побеждает чисто декоративный независимо от порядка. Между двумя слотами одного вида побеждает объявленный последним. Предупреждение с указанием ячейки записывается в лог один раз.

Действия по клику​

interactionList сопоставляет тип клика с командами и триггерами. Доступные типы: LEFT_CLICK, RIGHT_CLICK, SHIFT_LEFT_CLICK, SHIFT_RIGHT_CLICK, MIDDLE_CLICK, DOUBLE_CLICK, от NUMBER_KEY_1 до NUMBER_KEY_9, DROP, DROP_ALL и SWAP_OFFHAND.

  • commands выполняются от имени консоли. %player% заменяется именем игрока, а плейсхолдеры PlaceholderAPI разрешаются первыми.
  • triggers запускают записи TypeWriter для игрока. Собственные triggers и modifiers слота срабатывают при каждом левом или правом клике либо при совпадении конкретного взаимодействия.
  • closeMenu закрывает окно после действия. executeReturn возвращает к предыдущему меню.

Команды, начинающиеся с gui:, обрабатывает сам GUI:

КомандаЭффект
gui:closeЗакрывает меню.
gui:backЗаново открывает предыдущее меню сессии.
gui:open <entry_id> или gui:action <entry_id>Запускает другую запись, обычно другой Open GUI.
gui:view <view_id>Переключается на другое представление без закрытия инвентаря.
gui:page <delta> [layout_id]Сдвигает макет paginated или leaderboard на указанное число страниц.
gui:scroll <dx> <dy> [layout_id]Прокручивает макет scrollable.
gui:refreshНемедленно перерисовывает меню.
gui:sound <sound_key>Воспроизводит игроку звук.

Открытие, возврат и закрытие​

Open GUI, открытый из другого меню, помещается в историю сессии, поэтому gui:back или executeReturn возвращает к нему. Закрытие клавишей Escape завершает сессию. Открытие макета book сначала завершает текущую сессию.

Задайте audio, чтобы воспроизводить звуки при открытии, закрытии, прокрутке и клике. Задайте autoRefreshTicks, чтобы перерисовывать меню каждые N тиков, пока оно открыто, — именно благодаря этому плейсхолдеры в названиях и описаниях обновляются как счётчик или таймер.

Представления, вкладки и наследование​

views превращают один open_gui в несколько экранов с общей оболочкой. Фрейм (frame), у которого layoutId равен @view, заполняется макетом активного представления: сначала явным соответствием frames представления, затем макетом с именем <view id>_<frame id>, затем теми же поисками по parentId представления. Пометьте предмет-вкладку buttonPrefix view: и задайте buttonType равным id представления — по клику он переключит представление и будет подсвечен, пока оно активно. Заголовок представления допускает {breadcrumb}, {view} и {root}.

baseMenuId указывает на другой Open GUI и объединяет его layoutPool, views и storagePool с вашими: макет с тем же id заменяет унаследованный. Подробности — в разделе Представления, вкладки и наследование.

Слоты хранилища​

Артефакт GUI Storage хранит предметы для каждого игрока или группы. Объявите повторно используемые конфигурации в storagePool записи, затем задайте предмету storageId или используйте макет storage. В названиях и описаниях предметов слота хранилища допускаются {stored_name}, {stored_amount} и {stored_max}. {score_raw} и {value_<key>} также доступны для строк таблицы лидеров с source.

Привязки кликов по умолчанию, которые можно изменить в GUI Global Settings:

ДействиеКлик по умолчанию
Положить один предмет с курсораЛевый клик
Положить всю стопку с курсораShift + левый клик
Взять один предметПравый клик
Забрать всёЛевый клик
Взять стопкуShift + правый клик
Заполнить из инвентаряОбмен с левой рукой (F)
Выбросить всё на землюВыброс (Q)

dropOnClose выбрасывает то, что ещё хранится, под ноги игроку, когда меню по-настоящему закрывается: по Escape или при отключении, но не когда игрок переходит в другое меню.

Расширенный инвентарь​

extendToPlayerInventory показывает собственные 36 слотов игрока как четыре дополнительных ряда, давая холст из десяти рядов (y от 0 до 9). Это работает только на стороне клиента: настоящий инвентарь никогда не изменяется и восстанавливается при закрытии меню, а предметы нельзя забрать из нижних рядов. Требуется guiType CUSTOM с size SIZE_54. Корневой макет, у которого id заканчивается на _extended, включает эту возможность сам.

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

У GUI нет файла конфигурации. Его настраивают две необязательные записи manifest:

  • GUI Extension Configuration включает логирование debug и параметр hideVanillaItemStats (включён по умолчанию), который скрывает строки урона атаки, прочности и зачарований на кнопках меню.
  • GUI Global Settings задаёт привязки кликов хранилища и предметы-соединители дерева навыков.

Плейсхолдеры​

ПлейсхолдерВозвращает
%typewriter_gui_storage_amount_<entry_id>_<slot_index>%Число предметов, хранящихся у игрока в записи GUI Storage, 0, если пусто.
%typewriter_gui_storage_has_<entry_id>_<slot_index>%true, если в слоте есть предмет, иначе false.

<slot_index> — это y * 9 + x слота хранилища. Эти плейсхолдеры всегда читают собственное хранилище игрока, а не общее групповое.

Внутри меню расширение заменяет следующие токены: {stored_name}, {stored_amount}, {stored_max} (слоты хранилища), {page}, {next_page}, {prev_page}, {total_pages} и {page_indicator} (кнопка INDICATOR макета paginated), а также {rank}, {name}, {score}, {group}, {world} и {score_<fact_id>} (строки таблицы лидеров).

Записи​

Записей: 6, сгенерированы из исходного кода расширения.

Действия1
Артефакты2
Манифесты3

Устранение неполадок​

Меню открывается пустым. mainLayoutId пуст или не совпадает ни с одним id макета в layoutPool (id чувствительны к регистру). При использовании baseMenuId пустой mainLayoutId берётся у родителя. Проверка при запуске сообщает в консоли о неразрешённом главном макете.

Слот отсутствует, а консоль пишет «falls outside the grid». Предмет оказался при отрицательных x или y либо за столбцом 8. Обычно это следствие слишком большого count, который считает слоты. В логе указаны макет и отклонённые координаты.

Консоль пишет «Slot overlap ... gap». Два слота занимают одну ячейку. gap — это шаг: 1 размещает слоты вплотную, а 2 оставляет один пустой слот между ними, поэтому авторы, которые читают gap: 1 как «один промежуток», получают копии, накладывающиеся на соседей друг друга. Измените gap или переместите один из слотов.

Слот виден администраторам, но не игрокам. В viewPermission указано право, которое есть только у операторов. Пустые значения игнорируются, но опечатка — это реальный узел, доступный только операторам. То же правило действует для viewPermission представления.

Кнопка отображается, но ничего не делает. Проверьте clickPermission, затем cooldownTicks, затем criteria. Если у слота есть buttonType, его buttonPrefix должен совпадать с расширением, которое его предоставляет; незанятый тег сохраняет ваш interactionList, но больше ничего. Команды выполняются от имени консоли, поэтому команда, которой нужен отправитель-игрок, молча завершается ошибкой.

Прокручиваемое содержимое не двигается. Проверьте, что содержимое больше окна (virtualWidth и virtualHeight): стрелка показывается, только пока в её направлении есть что прокручивать. При отключённом showDefaultButtons и без buttons стрелок нет вообще. Стрелка по умолчанию также уступает место, если её ячейка уже занята предметом содержимого, кнопкой или декорацией: в консоль ничего не пишется, поэтому переместите её через scrollArrows в GUI Settings или добавьте собственные buttons с direction и step вне прокручиваемой области.

Таблица лидеров показывает только игроков в сети. Привяжите артефакт GUI Leaderboard Population в поле population таблицы лидеров, чтобы сохранять последние известные значения игроков не в сети.

Расширенное меню не показывает десять рядов. extendToPlayerInventory требует guiType CUSTOM и size SIZE_54.

Связанные расширения​

  • Shops — меню магазинов на основе макетов GUI и маркера shop_button:.
  • Quest Codex — меню журнала квестов, построенное на том же шасси open_gui.