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

Пользовательский ввод

Автор меню

Как сохранить ввод игрока и переиспользовать его внутри меню.

Почти каждый активатор хранит своё состояние - отдельное для каждого игрока. Это состояние мы называем Context. В контексте лежит любой объект:

  • команда, которую ввёл игрок;
  • блок, по которому он кликнул;
  • сущность или NPC, по которому он кликнул;
  • регион WorldGuard, в который он вошёл;
  • и так далее.

У каждого свежеоткрытого через активатор меню свой контекст. AbstractMenus даёт доступ к нему прямо через плейсхолдеры.

Достаём данные контекста через экстракторы значений. Сами экстракторы описаны в разделе Экстракторы значений, здесь покажем только как обратиться к конкретному экстрактору через плейсхолдер.

Каждый активатор привязан к одному из готовых экстракторов и через него выдаёт плейсхолдеры своего контекста.

Формат плейсхолдера активатора:

%activator_<extractor placeholder>%

Любой плейсхолдер активатора начинается с activator_. <extractor placeholder> - это плейсхолдер из конкретного экстрактора (см. Экстракторы значений).

Как использовать контекстный плейсхолдер

Заголовок раздела «Как использовать контекстный плейсхолдер»
  1. Открой справочник активаторов.

  2. Найди свой активатор.

  3. Под каждым активатором есть ссылка на экстрактор - имя экстрактора одновременно ведёт на таблицу его плейсхолдеров.

    Тип экстрактора, который использует активатор

  4. Перейди по ссылке к таблице плейсхолдеров экстрактора.

  5. Выбери нужный плейсхолдер.

  6. Приклей к нему префикс activator_.

  7. Вставь получившийся %activator_*% куда угодно в меню.

Пример 1. Использование контекстных плейсхолдеров

Заголовок раздела «Пример 1. Использование контекстных плейсхолдеров»

Допустим, у нас активатор clickEntity:

activators {
clickEntity {
type: SHEEP
}
}

После клика по любой овце контекстные плейсхолдеры доступны в правилах, действиях и свойствах предметов. Напоминаем: формат - %activator_<extractor placeholder>%. Пример:

title: "Меню овцы"
size: 1
activators {
clickEntity {
type: SHEEP
}
}
items: [
{
slot: 0
material: CAKE
name: "Имя овцы: %activator_entity_custom_name%"
click {
message: "&aТекущая локация овцы: %activator_entity_loc_x%, %activator_entity_loc_y%, %activator_entity_loc_z%"
}
}
]

Здесь мы взяли плейсхолдеры экстрактора entity_custom_name, entity_loc_x, entity_loc_y и entity_loc_z - все они описаны в Entity extractor.

Соберём что-нибудь поинтереснее. Хотим меню профиля: один игрок shift-кликнул по другому - открылось меню со статами того, по кому кликнули. Берём активатор shiftClickEntity.

title: "&b%activator_player_name%'s' profile"
size: 1
activators {
shiftClickEntity {
type: PLAYER
}
}
items: [
{
slot: 4
skullOwner: "%activator_player_name%"
name: "&e%activator_player_displayname%"
lore: [
"",
"&fLevel: %activator_player_level%",
"&fXP: %activator_player_exp%",
"&fHealth: %activator_player_health%",
"",
"&aClick, to say hello",
]
click {
command {
console: "tell %activator_player_name% Hello!"
}
}
}
]

Плейсхолдер сюда залез даже в заголовок меню - потому что инвентарь собирается уже после того, как активатор сформировал контекст. Дополнительно мы используем плейсхолдеры PlaceholderAPI, но с префиксом activator_: меню точно откроется только после клика по игроку (type: PLAYER).

Обычные плейсхолдеры здесь работают потому, что Entity Extractor принимает их, когда сущность - игрок. Об этом и других экстракторах подробно в разделе Экстракторы значений.

Теперь, если игрок shift-кликнет по другому, откроется такое меню:

Пример меню профиля игрока

Пример меню профиля игрока

Более сложные сценарии с контекстными плейсхолдерами лежат в разделе Примеры.

В AbstractMenus встроена мощная система команд - с аргументами, которые можно прокидывать в меню.

Здесь разбирается продвинутая форма активатора command с типизированными аргументами. Базовое описание активатора - на странице Активаторы.

Чтобы собрать команду с аргументами, объяви активатор command как объект. Параметры объекта:

КлючТипОписаниеОбязательный
nameStringБазовое имя командыtrue
aliasesСписок строкАлиасы базового имениfalse
errorStringКастомное сообщение об ошибкеfalse
helpStringКастомный префикс сообщения помощиfalse
argsСписок строк или объектовАргументы командыfalse
overrideBooleanПопытаться переопределить команду из другого плагинаfalse

В error можно вставить %s - туда подставится сообщение об ошибке от конкретного аргумента.

В help тоже работает %s - подставится автогенерируемая справка по команде на основе её структуры.

Пример с error и help:

command {
name: "mycmd"
error: "&cНеверный ввод: %s"
help: "&eСтруктура команды: %s"
}

Поле args - список, в котором аргументы задаются одной из двух форм: простой или типизированной.

Активатор command пробрасывает введённые значения в плейсхолдеры через Command extractor. Пример - ниже.

Простые аргументы - это просто список ключей. Каждый аргумент - строка, ввести можно что угодно. Пример:

command {
name: "mycmd"
args: [ "myarg1", "myarg2" ]
}

После перезагрузки AbstractMenus ждёт от игрока команду в формате:

/mycmd <myarg1> <myarg2>

Если игрок указал все аргументы - меню откроется. Если нет - получит ошибку.

Чтобы достать введённые значения, используй контекстные плейсхолдеры по принципу из Контекста активатора: смотри, какие плейсхолдеры даёт активатор, и приклеивай префикс activator_. Пример:

message: "Ты ввёл %activator_cmd_arg_myarg1% и %activator_cmd_arg_myarg2%"

Типизированный аргумент требует от игрока ввод определённого типа. Не подходит - получает ошибку.

Доступные типы:

  • string - простая строка без пробелов, можно ввести что угодно.

  • number - любое число, float или integer. Если из ввода не парсится число, аргумент падает.

  • integer - только целые числа. Падает, если ввод не парсится в integer.

  • player - имя онлайн-игрока. На tab-комплите подсказывает всех онлайн-игроков, падает, если такого нет.

  • choice - выбор из заранее заданных строковых опций. Опции подсказываются на tab-комплите, игрок должен выбрать одну из них.

Каждый типизированный аргумент - объект с параметрами. Общие поля для всех:

КлючТипОписаниеОбязательный
keyStringУникальное имя аргумента, которое будет использоваться в плейсхолдерахtrue
typeStringТип аргумента. См. все типы вышеtrue
errorStringКастомное сообщение об ошибкеfalse
defaultStringЗначение по умолчанию. Делает аргумент опциональнымfalse
command {
name: "mycmd"
args: [
{
key: "amount"
type: number
}
]
}

Чтобы достать значение, используем плейсхолдер:

message: "&eЧисло: %activator_cmd_arg_amount%"

У типа choice есть дополнительное поле options - список строк, по одному элементу на каждую опцию.

command {
name: "mycmd"
args: [
{
key: "variant"
type: choice
options: ["opt1", "opt2", "opt3"]
}
]
}

Выбранную опцию достаём так:

message: "&eВыбрано %activator_cmd_arg_variant%"

Аргумент player принимает только имя онлайн-игрока и подсказывает их на tab-комплите.

command {
name: "mycmd"
args: [
{
key: "username"
type: player
}
]
}

Имя игрока достаём так:

message: "&eИгрок: %activator_cmd_arg_username%"

Использование обычных плейсхолдеров для аргумента player

Заголовок раздела «Использование обычных плейсхолдеров для аргумента player»

У player есть одна приятная фишка. AbstractMenus сохраняет введённого игрока и даёт доступ к его обычным плейсхолдерам. Пример:

command {
name: "mycmd"
args: [
{
key: "player1"
type: player
},
{
key: "player2"
type: player
}
]
}

Допустим, нам нужен уровень обоих игроков. Command extractor умеет это и другое - формат плейсхолдера у него <key>:<placeholder> (см. Command extractor): сначала ключ аргумента, потом нужный плейсхолдер. Нам нужен player_level, итог:

%activator_player1:player_level%
и
%activator_player2:player_level%

Подробнее про поле default. Бывает, аргумент нужно сделать опциональным. Например, делаем меню профиля: если игрок ввёл имя - откроется профиль того игрока, если нет - своё.

Для такого добавляется значение по умолчанию. Внутри работают обычные плейсхолдеры. Пример:

command {
name: "profile"
args: [
{
key: "user"
type: player
default: "%player_name%"
}
]
}

При /profile аргумент user будет равен имени того, кто ввёл команду.

При /profile Notch - Notch.

Тут есть ограничение: опциональный аргумент может быть только один, и стоять обязан последним. Дело в парсере: при двух и более опциональных он не сможет понять, какой аргумент именно ты ввёл.

Финальный пример. Открытие меню профиля по команде

Заголовок раздела «Финальный пример. Открытие меню профиля по команде»

Возьмём пример из Меню личного профиля и переделаем. Меняем shiftClickEntity на command, команда принимает имя игрока:

title: "%activator_user:player_name%'s profile"
size: 1
activators {
command {
name: "profile"
args: [
{
key: "user"
type: player
default: "%player_name%"
}
]
}
}
items: [
{
slot: 4
skullOwner: "%activator_user:player_name%"
name: "&e%activator_user:player_displayname%"
lore: [
"",
"&fLevel: %activator_user:player_level%",
"&fKills: %activator_user:statistic_mob_kills%",
"&fDeaths: %activator_user:statistic_deaths%",
"",
"&aClick, to say hello",
]
click {
command {
console: "tell %activator_user:player_name% Hello!"
}
}
}
]

Плейсхолдеры тоже подогнали под формат Command Extractor. Результат ниже.

Как работают команды

Иногда нужно перебить команду другого плагина. Например, есть сторонний плагин с /kit.

Допустим, мы хотим, чтобы по той же команде открывалось наше меню со списком китов. По умолчанию AbstractMenus регистрирует команду как обычно - и её может перетереть любой другой плагин.

Чтобы перебить чужую команду, добавь в активатор command параметр override: true. Пример:

activators {
command {
name: "kit"
aliases: ["kits"]
override: true
}
}

Команда с override: true вешается ещё и как слушатель чата, а не только как обычная команда. Так её можно “перебить” у стороннего плагина, даже если AbstractMenus загрузился позже.

Когда игрок такую команду ввёл, плагин обрабатывает её как обычно и отменяет дальнейшую обработку сообщения - чтобы у настоящего “владельца команды” она не отработала.

Действие inputChat запрашивает у игрока текст в чате. Структура такая:

ПараметрТипОписаниеОбязательный
intoStringИмя переменной, в которую сохранятся данныеtrue
globalBooleanЕсли true, данные сохранятся в глобальной переменной. По умолчанию falsefalse
cancelOnString”Стоп-слово” или фраза, которая отменит ожидание ввода. Если ввод отменён, выполнятся действия из onCancel вместо onInputfalse
onInputОбъектДействия после успешного вводаfalse
onCancelОбъектДействия для ввода, отменённого стоп-словомfalse

Обязательный только into - имя переменной. Когда игрок что-то пишет в чат, плагин кладёт текст в переменную с этим именем. Прочитать её потом можно откуда угодно через плейсхолдер переменной.

Базовый пример:

slot: 0
material: STONE
click {
message: "Enter player name"
inputChat {
into: "input_username"
}
}

При клике на предмет меню закроется и пришлёт сообщение - дальше игрок должен что-то написать в чат.

Чтобы выполнить действия после ввода, используй блок onInput. Пример:

slot: 0
material: STONE
click {
message: "Enter player name"
inputChat {
into: "input_username"
onInput {
command: {
console: "say Hello, %varp_:input_username%!"
}
}
}
}

Результат:

Ожидание ввода

Когда игрок что-нибудь напишет в чат, все увидят Hello, <text>!, где <text> - то, что он ввёл.

Ввод завершён

Чтобы игрок мог отменить ввод, добавь в действие параметр cancelOn. Пример:

slot: 0
material: STONE
click {
message: "Enter player name"
inputChat {
into: "input_username"
cancelOn: "cancel"
onInput {
command: {
console: "say Hello, %varp_:input_username%"
}
}
onCancel {
message: "Ok, do not write anything"
}
}
}

Заодно подцепили блок onCancel - чтобы отправить игроку сообщение при отмене. Если он введёт cancel, плагин перестанет ждать ввод и выполнит действия из onCancel, если они есть.

Ввод отменён стоп-словом

Не всё, что обычно работает в меню, доступно внутри onInput и onCancel.

Меню в это время закрыто, поэтому в этих блоках работают только действия, которые не лезут в инвентарь меню. Нельзя использовать refreshMenu, closeMenu, openMenu и подобные.

Контекстные плейсхолдеры тоже не работают - так устроен жизненный цикл меню. Доступны только обычные плейсхолдеры и переменные.