Парсинг аргументов
API конструктора команд предоставляет мощный парсер аргументов. Он преобразует введённые данные как в базовые типы Java (целые числа, логические значения, строки), так и в игровые объекты (игроки, миры, типы блоков и т.д.). Парсер поддерживает необязательные аргументы и флаги. Также он поддерживает автозавершение аргументов при нажатии клавиши TAB.
Прошедшие парсинг аргументы сохраняются в объекты типа CommandContext
. Если парсер возвращает один объект, то можно получить его при помощи args.<T>getOne(String key)
(вместо T
введите тип значения). Необязательные и слабые аргументы могут возвращать Optional.empty()
.
Многие парсеры могут возвращать более одного объекта (например, несколько игроков с соответствующим именем). В этом случае, Вам необходимо использовать метод args.<T>getAll(String key)
для получения коллекции Collection
возможных вариантов. Если этого не сделать, будет сгенерировано исключение!
При создании команды, учтите, может ли аргумент возвращать множество значений, например, можно ли в качестве аргумента типа Player использовать селектор для выбора нескольких игроков. В таком случае игроки понадобится ввести всего лишь одну простую команду. Например: /tell @a Who took the cookies?
.
Совет
Вы можете использовать элемент GenericArguments#onlyOne(CommandElement) для ограничения количества возвращаемых значений до одного, и тогда вы сможете безопасно использовать args.<T>getOne(String)
. Однако пользователь всё равно получит сообщение, если попытается ввести более одного значения.
Для создания новых CommandElement (аргументы команды), используете фабричный класс GenericArguments. Многие элементы команды требуют короткий текстовый ключ, который отображается в ошибках и в сообщениях помощи.
Используя метод CommandSpec.Builder#arguments(CommandElement…), можно добавить CommandElement
в конструктор команды. Можно добавить несколько CommandElement
в конструктор, связав таким образом аргументы в цепочку (например, /msg <player> <msg>
). Аналогичного эффекта можно добиться, обернув объекты CommandElement
в объект GenericArguments#seq(CommandElement…).
Пример: Создание команды с несколькими аргументами
import org.spongepowered.api.Sponge;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.command.CommandException;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.command.args.CommandContext;
import org.spongepowered.api.command.args.GenericArguments;
import org.spongepowered.api.command.spec.CommandExecutor;
import org.spongepowered.api.command.spec.CommandSpec;
PluginContainer plugin = ...;
CommandSpec myCommandSpec = CommandSpec.builder()
.description(Text.of("Send a message to a player"))
.permission("myplugin.command.message")
.arguments(
GenericArguments.onlyOne(GenericArguments.player(Text.of("player"))),
GenericArguments.remainingJoinedStrings(Text.of("message")))
.executor((CommandSource src, CommandContext args) -> {
Player player = args.<Player>getOne("player").get();
String message = args.<String>getOne("message").get();
player.sendMessage(Text.of(message));
return CommandResult.success();
})
.build();
Sponge.getCommandManager().register(plugin, myCommandSpec, "message", "msg", "m");
Overview of the GenericArguments
command elements
Элемент команды |
Описание |
Количество и тип значения |
---|---|---|
|
Не требует аргументов. Это обычное поведение |
|
Базовые типы Java |
||
|
Требует аргумент типа String. |
один |
|
Соединяет все оставшиеся аргументы разделенные пробелами (может быть использовано для команд-сообщений). |
один |
|
Требует аргумент типа boolean. |
один |
|
Требует аргумент типа integer. |
один |
|
Требует аргумент типа double. |
один |
Игровые объекты |
||
|
Ожидает аргумент в виде онлайн-игрока. Может возвращать несколько игроков! |
несколько экземпляров |
|
Как |
несколько экземпляров |
|
Как |
несколько экземпляров |
|
Ожидает аргумент в виде мира (также включает выгруженные миры). |
несколько |
|
Ожидает аргумент в виде измерения ( |
несколько экземпляров |
|
Ожидает аргумент в виде |
один |
|
Ожидает аргумент в виде |
один |
|
Expect an argument that is a member of the specified CatalogType. |
multiple matching elements of the specified catalog type |
Шаблоны |
||
|
Return an argument that allows selecting from a limited set of values. |
one specified value |
|
Expect a literal sequence of arguments (e.g. |
one specified value |
|
Require the argument to be a key under the provided enum. |
multiple matching elements of the specified enum |
Утилиты Can be wrapped around command elements. The value type is inherited from the wrapped element. |
||
|
Builds a sequence of command elements (e.g. |
унаследованное |
|
Require a given command element to be provided a certain number of times. |
несколько унаследованных |
|
Require all remaining args to match the provided command element. |
несколько унаследованных |
|
Make the provided command element optional. Throws an error if the argument is of invalid format and there are no more args. |
унаследованное |
|
Сделайте предоставленный командный элемент необязательным. Не выдает ошибку, если аргумент имеет недопустимый формат и больше нет аргументов. |
унаследованное |
|
Returns a command element that matches the first of the provided elements that parses
(useful for command overloading, e.g. |
унаследованное |
|
Restricts the given command element to only insert one value into the context at the provided key. |
унаследованное |
|
Returns a builder for command flags (e.g. См. Флаги команд |
Short Flag: one Long Flag: one Value Flag: inherited |
|
Requires the command sender to have the specified permission in order to use the given command argument |
унаследованное |
|
Requires the command sender to have the specified permission in order to use the given command argument. Does not throw an error if the user does not have the permission. |
унаследованное |
Совет
Больше информации доступно в Javadoc: GenericArguments.
Предупреждение
Не следует ожидать, что объекты CommandElement
вернут одно значение: многие из них поддерживают возврат множества значения, а некоторые - регулярные выражения и селекторы. Это сделано намеренно, т.к. это упрощает использование команд. Например: /tell @a BanditPlayer has the cookies!
. Чтобы быть уверенным в том, что будет возвращено только одно значение, используйте GenericArguments#onlyOne(CommandElement)
.
Пользовательские CommandElement’ы
Можно создать пользовательские командные элементы (например, URL-парсер или элемент Vector2i
), расширив абстрактный класс CommandElement
.
Метод CommandElement#parseValue(CommandSource, CommandArgs) должен получить необработанный аргумент в виде строки с помощью CommandArgs#next() и конвертировать его в объект. Если парсинг окажется неудачным, метод должен сгенерировать исключение ArgumentParseException.
Метод The CommandElement#complete(CommandSource, CommandArgs, CommandContext) должен использовать CommandArgs#peek() для прочтения следующего исходного аргумента. Этот метод возвращает список аргументов для автозавершения при нажатии клавиши TAB.
Пример: определение командного элемента Vector2i
В этом примере парсер читает два входных аргумента и преобразует их в вектор.
import com.flowpowered.math.vector.Vector2i;
import org.spongepowered.api.command.args.ArgumentParseException;
import org.spongepowered.api.command.args.CommandArgs;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.command.args.CommandElement;
import java.util.Collections;
import java.util.List;
public class Vector2iCommandElement extends CommandElement {
protected Vector2iCommandElement(Text key) {
super(key);
}
@Override
protected Object parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException {
String xInput = args.next();
int x = parseInt(xInput, args);
String yInput = args.next();
int y = parseInt(yInput, args);
return new Vector2i(x, y);
}
private int parseInt(String input, CommandArgs args) throws ArgumentParseException {
try {
return Integer.parseInt(input);
} catch(NumberFormatException e) {
throw args.createError(Text.of("'" + input + "' is not a valid number!"));
}
}
@Override
public List<String> complete(CommandSource src, CommandArgs args, CommandContext context) {
return Collections.emptyList();
}
@Override
public Text getUsage(CommandSource src) {
return Text.of("<x> <y>");
}
}
Пример: использование командного элемента Vector2i`
// /plottp <x> <y>
CommandSpec myCommandSpec = CommandSpec.builder()
.description(Text.of("Teleport to a plot"))
.permission("myplugin.command.plot.tp")
.arguments(new Vector2iCommandElement(Text.of("coordinates")))
.executor(new MyCommandExecutor())
.build();
Совет
Просмотрите исходный код класса GenericArguments
, чтобы увидеть больше примеров.
Использование селектора в пользовательских командных элементах
Sponge предоставляет поддержку парсинга селекторов, т.е. вы можете использовать их в собственных CommandElements. Использование селекторов состоит из двух частей: парсинга (получения Selector из строки) и получения (resolving) множества объектов Entity, выбранных селектором.
Для парсинга строки, содержащей селектор, используйте метод Selector#parse(String), передав ему весь селектор, включая символ @
. Таким образом, вы превратите строку с объект типа Selector
, с которым сможете вести дальнейшую работу. Учтите, что если строка не представляет собой допустимый селектор, будет сгенерировано исключение IllegalArgumentException.
Для получения данных из селектора, используйте метод Selector#resolve(CommandSource). Он вернет множество объектов Entity
, выбранных селектором.
В примере ниже метод parseValue
класса CommandElement
пытается пропарсить селектор и возвращает список сущностей, основанный на расположении источника команды. Если строка не начинается с символа @
, будет сгенерировано исключение, показывающее, что аргумент не является селектором.
@Override
protected Object parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException {
String nextArg = args.next();
if (nextArg.startsWith("@")) {
Set<Entity> selectedEntities;
try {
selectedEntities = Selector.parse(nextArg).resolve(source);
} catch (IllegalArgumentException e) {
throw args.createError(Text.of("Could not parse selector."));
}
if (selectedEntities.isEmpty()) {
throw args.createError(Text.of("No entities selected."));
}
return selectedEntities;
}
throw args.createError(Text.of("Not a selector."));
}
Совет
В исходном коде SelectorCommandElement вы можете посмотреть, каким образом происходит парсинг селектора в стандартном CommandElements
.