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
Next revision
Previous revision
Last revisionBoth sides next revision
zh_cn:tutorial:command_argument_types [2023/04/20 11:06] 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 73: Line 106:
 import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
 import net.minecraft.text.Text; import net.minecraft.text.Text;
-import net.minecraft.util.SystemUtil; 
  
 import java.util.ArrayList; import java.util.ArrayList;
Line 89: Line 121:
     public static <S> UUID getUuid(String name, CommandContext<S> context) {     public static <S> UUID getUuid(String name, CommandContext<S> context) {
         // 注意你应该假设 CommandContext 中包含的 CommandSource 是一个泛型类型。         // 注意你应该假设 CommandContext 中包含的 CommandSource 是一个泛型类型。
-        // 如果你需要访问 ServerCommandSource,确保你在强转之前验证了源。+        // 如果你需要访问 ServerCommandSource,确保你在强转之前验证了命令源。
         return context.getArgument(name, UUID.class);         return context.getArgument(name, UUID.class);
     }     }
  
-    private static final Collection<String> EXAMPLES = SystemUtil.consume(new ArrayList<>(), list -> { +    private static final Collection<String> EXAMPLES = List.of
-        list.add("765e5d33-c991-454f-8775-b6a7a394c097"); // i509VCB: 用户名 The_1_gamers +        "765e5d33-c991-454f-8775-b6a7a394c097"// i509VCB: 用户名 The_1_gamers 
-        list.add("069a79f4-44e9-4726-a5be-fca90e38aaf5"); // Notch +        "069a79f4-44e9-4726-a5be-fca90e38aaf5"// Notch 
-        list.add("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6"); // Dinnerbone +        "61699b2e-d327-4a01-9f1e-0ea8c3f06bc6"  // Dinnerbone 
-    });+    );
  
     @Override     @Override
Line 130: Line 162:
         // Brigadier 支持显示示例,表示这个命令应该像是什么样子,这应该包含一个集合,         // Brigadier 支持显示示例,表示这个命令应该像是什么样子,这应该包含一个集合,
         // 集合的内容是此类型能够返回的参数。         // 集合的内容是此类型能够返回的参数。
-        // 这主要用于计算共享了同个的难懂的命令+        // 这主要用于检测二义性,即种参数可能会被作为另一种参数解析
         return EXAMPLES;         return EXAMPLES;
     }     }
zh_cn/tutorial/command_argument_types.txt · Last modified: 2024/04/15 07:24 by solidblock