User Tools

Site Tools


zh_cn:tutorial:command_argument_types

This is an old revision of the document!


命令参数类型

Brigadier 支持自定义的参数类型,本页会展示如何创建一个简单的参数类型。

注意:自定义的参数类型要求客户端也正确注册,如果是服务器的插件,请考虑使用已存在的参数类型和一个自定义的建议提供器。

本例中,我们将会创建一个 UuidArgumentType。

首先创建一个类并继承 ArgumentType。注意 ArgumentType 是泛型,因此泛型会定义这个 ArgumentType 会返回什么。

public class UuidArgumentType implements ArgumentType<UUID> {

参数类型需要实现 parse 方法,该方法返回的类型要符合泛型的类型。

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

所以的解析都发生在此方法中。此方法会根据命令行中提供的参数返回一个对象,或者抛出一个 CommandSyntaxException 即解析失败。

接下来你会存在当前指针(cursor)的位置,这样你可以截取子字符串,截出特定的参数。指针总是出现在参数在命令行中出现的开始的位置。

  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. // 尽管应该使用正常的 create 方法。
  8. throw new SimpleCommandExceptionType(Text.literal(ex.getMessage())).createWithContext(reader);
  9. }

ArgumentType 完成了,你的客户端却会拒绝解析参数并抛出错误。这是因为服务器会告诉客户端这是什么参数类型。而客户端不会解析它不知道的参数类型。要解决这个问题,我们需要在 ModInitializer 中注册一个 ArgumentSerializer。对于更加复杂的参数类型,你可能还需要创建自己的 ArgumentSerializer

  1. ArgumentTypeRegistry.registerArgumentType(new Identifier("tutorial", "uuid"), UuidArgumentType.class, ConstantArgumentSerializer.of(UuidArgumentType::uuid));
  2. // 这个参数会创建 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.Text;
  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.  * 代表一个返回 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. // 注意你应该假设 CommandContext 中包含的 CommandSource 是一个泛型类型。
  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: 用户名 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. // 我们返回我们的类型,在这个例子中,解析器会认为类型已经正确解析,并继续。
  52. } catch (Exception ex) {
  53. // UUID 在由字符串生成时,可能会抛出异常,因此我们捕获这个异常,并将其包装成 CommandSyntaxException 类型。
  54. // 创建时会带有环境,告诉 Brigadier,根据这个环境来告诉玩家,命令在哪里解析失败了。
  55. // 尽管应该使用正常的 create 方法。
  56. throw new SimpleCommandExceptionType(Text.literal(ex.getMessage())).createWithContext(reader);
  57. }
  58. }
  59.  
  60. @Override
  61. public Collection<String> getExamples() {
  62. // Brigadier 支持显示示例,表示这个命令应该像是什么样子,这应该包含一个集合,
  63. // 集合的内容是此类型能够返回的参数。
  64. // 这主要用于计算共享了同一个的难懂的命令。
  65. return EXAMPLES;
  66. }
  67. }
zh_cn/tutorial/command_argument_types.1681988812.txt.gz · Last modified: 2023/04/20 11:06 by solidblock