ru:tutorial:commands:argument_types

Пользовательские типы аргументов

Примечание: статья в разработке.

Brigadier поддерживает пользовательские типы аргументов, и в этом разделе показано, как создать простой тип аргумента.

Внимание: Пользовательские аргументы требуют правильной регистрации установки клиентского мода! Если вы создаете серверный плагин, рассмотрите возможность использования существующего типа аргумента и поставщика пользовательских предложений вместо этого.

Для этого примера мы создадим UuidArgumentType.

Сначала создайте класс, который расширяет ArgumentType. Обратите внимание, что ArgumentType является дженериком, поэтому общий тип будет определять, какой тип будет возвращать ArgumentType:

  1. public class UuidArgumentType implements ArgumentType<UUID> {

ArgumentType требует, чтобы вы реализовали метод parse, тип, который он возвращает, будет соответствовать типу дженерика:

@Override
public UUID parse(StringReader reader) throws CommandSyntaxException {

Именно в этом методе будет происходить весь ваш синтаксический анализ. Либо этот метод вернет объект на основе аргументов, предоставленных в командной строке, либо выдаст CommandSyntaxException, и синтаксический анализ завершится ошибкой.

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

  1. int argBeginning = reader.getCursor(); // Начальная позиция курсора находится в начале аргумента.
  2. if (!reader.canRead()) {
  3. reader.skip();
  4. }

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

  1. while (reader.canRead() && reader.peek() != ' ') { // "peek" предоставляет символ в текущем положении курсора.
  2. reader.skip(); // Сообщает StringReader переместить курсор в следующую позицию.
  3. }

Затем мы спросим у StringReader, какая текущая позиция курсора является подстрокой нашего аргумента из командной строки:

  1. String uuidString = reader.getString().substring(argBeginning, reader.getCursor());

Теперь, наконец, мы проверяем, верен ли наш аргумент, и анализируем конкретный аргумент по своему вкусу, а также выдаем исключение, если синтаксический анализ завершается неудачей:

  1. try {
  2. UUID uuid = UUID.fromString(uuidString); // Теперь наша действительная логика.
  3. return uuid; // И мы возвращаем наш тип, в этом случае анализатор будет считать, что этот аргумент был проанализирован правильно, а затем двигаться дальше.
  4. } catch (Exception ex) {
  5. // UUID могут выдавать исключение, когда они создаются строкой, поэтому мы перехватываем исключение и переупаковываем его в тип CommandSyntaxException.
  6. // Создание с контекстом сообщает Brigadier'у предоставить некоторый контекст, чтобы сообщить пользователю, где произошла ошибка команды.
  7. // Хотя можно было бы использовать обычный метод создания.
  8. throw new SimpleCommandExceptionType(new LiteralText(ex.getMessage())).createWithContext(reader);
  9. }

ArgumentType выполнен, однако ваш клиент откажется анализировать аргумент и выдаст ошибку. Это происходит потому, что сервер сообщит клиенту, к какому типу аргумента относится командный узел. И клиент не будет анализировать какие-либо типы аргументов, которые он не знает, как анализировать. Чтобы исправить это, нам нужно зарегистрировать ArgumentSerializer в вашем ModInitializer. Для более сложных типов аргументов вам может потребоваться создать свой собственный ArgumentSerializer:

  1. ArgumentTypes.register("mymod:uuid", UuidArgumentType.class, new ConstantArgumentSerializer(UuidArgumentType::uuid));
  2. // Аргумент должен быть тем, что создаст ArgumentType.

И вот весь ArgumentType:

UuidArgumentType.java
  1. import com.mojang.brigadier.StringReader;
  2. import com.mojang.brigadier.arguments.ArgumentType;
  3. import com.mojang.brigadier.context.CommandContext;
  4. import com.mojang.brigadier.exceptions.CommandSyntaxException;
  5. import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
  6. import net.minecraft.text.LiteralText;
  7. import net.minecraft.util.SystemUtil;
  8.  
  9. import java.util.ArrayList;
  10. import java.util.Collection;
  11. import java.util.UUID;
  12.  
  13. /**
  14.  * Представляет ArgumentType который будет возвращать UUID.
  15.  */
  16. public class UuidArgumentType implements ArgumentType<UUID> {
  17. public static UuidArgumentType uuid() {
  18. return new UuidArgumentType();
  19. }
  20.  
  21. public static <S> UUID getUuid(String name, CommandContext<S> context) {
  22. // Обратите внимание, что вы должны предполагать, что CommandSource, заключенный внутри CommandContext, всегда будет универсальным типом.
  23. // Если вам нужно получить доступ к ServerCommandSource, убедитесь, что источник является источником команд сервера перед приведением.
  24. return context.getArgument(name, UUID.class);
  25. }
  26.  
  27. private static final Collection<String> EXAMPLES = SystemUtil.consume(new ArrayList<>(), list -> {
  28. list.add("765e5d33-c991-454f-8775-b6a7a394c097"); // i509VCB: Username The_1_gamers
  29. list.add("069a79f4-44e9-4726-a5be-fca90e38aaf5"); // Notch
  30. list.add("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6"); // Dinnerbone
  31. });
  32.  
  33. @Override
  34. public UUID parse(StringReader reader) throws CommandSyntaxException {
  35. int argBeginning = reader.getCursor(); // Начальная позиция курсора находится в начале аргумента.
  36. if (!reader.canRead()) {
  37. reader.skip();
  38. }
  39.  
  40. // Теперь мы проверяем содержимое аргумента до тех пор, пока либо не достигнем конца командной строки (когда canRead становится false).
  41. // В противном случае мы идем до тех пор, пока не достигнем пробела, что означает следующий аргумент
  42. while (reader.canRead() && reader.peek() != ' ') { // "peek" предоставляет символ в текущем положении курсора.
  43. reader.skip(); // Сообщает StringReader переместить курсор в следующую позицию.
  44. }
  45.  
  46. // Теперь мы подстроим конкретную часть, которую мы хотим видеть, используя начальную позицию курсора и концы, с которых начинается следующий аргумент.
  47. String uuidString = reader.getString().substring(argBeginning, reader.getCursor());
  48. try {
  49. UUID uuid = UUID.fromString(uuidString); // Теперь наша действительная логика.
  50. return uuid; // И мы возвращаем наш тип, в этом случае анализатор будет считать, что этот аргумент был проанализирован правильно, а затем двигаться дальше.
  51. } catch (Exception ex) {
  52. // UUID могут выдавать исключение, когда они создаются строкой, поэтому мы перехватываем исключение и переупаковываем его в тип CommandSyntaxException.
  53. // Создание с контекстом сообщает Brigadier'у предоставить некоторый контекст, чтобы сообщить пользователю, где произошла ошибка команды.
  54. // Хотя можно было бы использовать обычный метод создания.
  55. throw new SimpleCommandExceptionType(new LiteralText(ex.getMessage())).createWithContext(reader);
  56. }
  57. }
  58.  
  59. @Override
  60. public Collection<String> getExamples() { // У Brigadier есть поддержка, чтобы показать примеры того, как должен выглядеть аргумент, он должен содержать коллекцию только аргументов, которые вернет этот тип. Это в основном используется для вычисления неоднозначных команд, которые имеют одинаковые
  61. return EXAMPLES;
  62. }
  63. }
ru/tutorial/commands/argument_types.txt · Last modified: 2022/03/03 12:45 by 127.0.0.1