User Tools

Site Tools


zh_cn:tutorial:command_argument_types

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Last revisionBoth sides next revision
zh_cn:tutorial:command_argument_types [2023/04/20 11:11] – fix type solidblockzh_cn:tutorial:command_argument_types [2024/04/15 07:14] solidblock
Line 3: Line 3:
 Brigadier 支持自定义的参数类型,本页会展示如何创建一个简单的参数类型。 Brigadier 支持自定义的参数类型,本页会展示如何创建一个简单的参数类型。
  
-注意:自定义的参数类型要求客户端也正确注册,如果是服务器的插件,请考虑使用已存在的参数类型和一个自定义的建议提供器。+**注意:**自定义的参数类型要求客户端也正确注册,如果是服务器的插件,请考虑使用已存在的参数类型和一个自定义的建议提供器。
  
-本例中,我们将会创建一个 UuidArgumentType。+===== 解析 ===== 
 +本例中,我们将会创建一个 ''UuidArgumentType''
  
-首先创建一个类并继承 ''ArgumentType''。注意 ''ArgumentType'' 是泛型,因此泛型会定义这个 ''ArgumentType'' 会返回什么。+首先创建一个类并继承 ''ArgumentType''。注意 ''ArgumentType'' 是泛型,因此泛型会定义这个 ''ArgumentType'' 会返回什么类型
  
 <code java> <code java>
Line 21: Line 22:
 所以的解析都发生在此方法中。此方法会根据命令行中提供的参数返回一个对象,或者抛出一个 ''CommandSyntaxException'' 即解析失败。 所以的解析都发生在此方法中。此方法会根据命令行中提供的参数返回一个对象,或者抛出一个 ''CommandSyntaxException'' 即解析失败。
  
-接下来你会存当前指针(cursor)的位置,这样你可以截取子字符串,截出特定的参数。指针总是出现在参数在命令行中出现的开始的位置。+接下来你会存当前指针(cursor)的位置,这样你可以截取子字符串,截出特定的参数。指针总是出现在参数在命令行中出现的开始的位置。
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-int argBeginning = reader.getCursor(); // 指针开始位置是参数开始位置。 +    int argBeginning = reader.getCursor(); // 指针开始位置是参数开始位置。 
-if (!reader.canRead()) { +    if (!reader.canRead()) { 
-    reader.skip(); +        reader.skip(); 
-}+    }
 </code> </code>
  
-现在抓取整个参数。你可能会有不同的标准,或像一些参数一样,检测到命令行中有 ''{'' 时会要求其能够闭合,具体取决于你的参数类型。对于 UUID,我们只需要指出参数结束时的指针的位置+现在抓取整个参数。你可能会有不同的标准,或像一些参数一样,检测到命令行中有 ''{'' 时会要求其能够闭合,具体取决于你的参数类型。
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-while (reader.canRead() && reader.peek() != ' ') { // “peek”提供了当前指针位置的字符。 +    while (reader.canRead() && reader.peek() != ' ') { // “peek”提供了当前指针位置的字符。 
-    reader.skip(); // 告诉 StringReader,将其指针移动到下一个位置。 +        reader.skip(); // 告诉 StringReader,将其指针移动到下一个位置。 
-}+    }
 </code> </code>
  
 接下来我们会从这个 ''StringReader'' 中,获取命令行中的指针位置的子字符串。 接下来我们会从这个 ''StringReader'' 中,获取命令行中的指针位置的子字符串。
  
-<code java [enable_line_numbers="true"]>String uuidString = reader.getString().substring(argBeginning, reader.getCursor());</code>+<code java [enable_line_numbers="true"]> 
 +    String uuidString = reader.getString().substring(argBeginning, reader.getCursor()); 
 +</code>
  
 最终,我们检查我们的参数是否正确,并解析我们的参数,如果解析失败则抛出异常。 最终,我们检查我们的参数是否正确,并解析我们的参数,如果解析失败则抛出异常。
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-try { +    public static final DynamicCommandExceptionType INVALID_UUID = new DynamicCommandExceptionType(o -> Text.literal("无效的uuid:" + o)); 
-    UUID uuid = UUID.fromString(uuidString); // 我们的正常逻辑。 + 
-    return uuid; // 我们返回我们的类型,在这个例子中,解析器会认为类型已经正确解析,并继续。 +    @Override 
-} catch (Exception ex) { +    public UUID parse(StringReader reader) throws CommandSyntaxException { 
-    // UUID 在由字符串生成时,可能会抛出异常,因此我们捕获这个异常,并将其包装成 CommandSyntaxException 类型。 +        // ... 
-    // 创建时会带有环境,告诉 Brigadier,根据这个环境来告诉玩家,命令在哪里解析失败了。 +        try { 
-    // 尽管应该使用正常的 create 方法。 +            UUID uuid = UUID.fromString(uuidString); // 我们的正常逻辑。 
-    throw new SimpleCommandExceptionType(Text.literal(ex.getMessage())).createWithContext(reader); +            return uuid; // 我们返回我们的类型,在这个例子中,解析器会认为类型已经正确解析,并继续。 
-}+        } catch (InvalidArgumentException ex) { 
 +            // UUID 在由字符串生成时,可能会抛出异常,因此我们捕获这个异常,并将其包装成 CommandSyntaxException 类型。 
 +            // 创建时会带有环境,告诉 Brigadier,根据这个环境来告诉玩家,命令在哪里解析失败了。 
 +            // 尽管也可以使用正常的 create 方法。 
 +            reader.setCursor(argBeginning); 
 +            throw INVALID_UUID.createWithContext(reader, ex.getMessage()); 
 +        } 
 +        // ... 
 +    }
 </code> </code>
 +
 +===== 定义参数示例 =====
 +有时候参数需要有一些示例,通常存储在作为静态常量字段的不可变集合中。示例是用于检测二义性的。
 +<code java>
 +    private static final Collection<String> EXAMPLES = List.of(
 +        "765e5d33-c991-454f-8775-b6a7a394c097", // i509VCB: Username The_1_gamers
 +        "069a79f4-44e9-4726-a5be-fca90e38aaf5", // Notch
 +        "61699b2e-d327-4a01-9f1e-0ea8c3f06bc6"  // Dinnerbone
 +    );
 +
 +    @Override
 +    public Collection<String> getExamples() {
 +        // Brigadier 支持显示示例,表示这个命令应该像是什么样子,这应该包含一个集合,
 +        // 集合的内容是此类型能够返回的参数。
 +        // 这主要用于检测二义性,即一种参数可能会被作为另一种参数解析。
 +        return EXAMPLES;
 +    }
 +</code>
 +
 +===== 注册参数类型 =====
  
 ''ArgumentType'' 完成了,你的客户端却会拒绝解析参数并抛出错误。这是因为服务器会告诉客户端这是什么参数类型。而客户端不会解析它不知道的参数类型。要解决这个问题,我们需要在 ''ModInitializer'' 中注册一个 ''ArgumentSerializer''。对于更加复杂的参数类型,你可能还需要创建自己的 ''ArgumentSerializer'' ''ArgumentType'' 完成了,你的客户端却会拒绝解析参数并抛出错误。这是因为服务器会告诉客户端这是什么参数类型。而客户端不会解析它不知道的参数类型。要解决这个问题,我们需要在 ''ModInitializer'' 中注册一个 ''ArgumentSerializer''。对于更加复杂的参数类型,你可能还需要创建自己的 ''ArgumentSerializer''
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-ArgumentTypeRegistry.registerArgumentType(new Identifier("tutorial", "uuid"), UuidArgumentType.class, ConstantArgumentSerializer.of(UuidArgumentType::uuid));  +ArgumentTypeRegistry.registerArgumentType( 
-// 这个参数会创建 ArgumentType。+  new Identifier("tutorial", "uuid"), 
 +  UuidArgumentType.class, ConstantArgumentSerializer.of(UuidArgumentType::uuid));  
 +// 参数会创建 ArgumentType。
 </code> </code>
  
-参数类型的完整代码会是这样:+===== 完整参数类型示例 =====
  
 <file java UuidArgumentType.java [enable_line_numbers="true"]> <file java UuidArgumentType.java [enable_line_numbers="true"]>
Line 129: Line 162:
         // Brigadier 支持显示示例,表示这个命令应该像是什么样子,这应该包含一个集合,         // Brigadier 支持显示示例,表示这个命令应该像是什么样子,这应该包含一个集合,
         // 集合的内容是此类型能够返回的参数。         // 集合的内容是此类型能够返回的参数。
-        // 这主要用于计算共享了同个的难懂的命令+        // 这主要用于检测二义性,即种参数可能会被作为另一种参数解析
         return EXAMPLES;         return EXAMPLES;
     }     }
zh_cn/tutorial/command_argument_types.txt · Last modified: 2024/04/15 07:24 by solidblock