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)的位置,这样你可以截取子字符串,截出特定的参数。指针总是出现在参数在命令行中出现的开始的位置。
int argBeginning = reader.getCursor(); // 指针的开始位置,是参数的开始位置。 if (!reader.canRead()) { reader.skip(); }
现在抓取整个参数。你可能会有不同的标准,或像一些参数一样,检测到命令行中有 {
时会要求其能够闭合,具体取决于你的参数类型。对于 UUID,我们只需要指出参数结束时的指针的位置。
while (reader.canRead() && reader.peek() != ' ') { // “peek”提供了当前指针位置的字符。 reader.skip(); // 告诉 StringReader,将其指针移动到下一个位置。 }
接下来我们会从这个 StringReader
中,获取命令行中的指针位置的子字符串。
最终,我们检票我们的参数是否正确,并解析我们的参数,如果解析失败则抛出异常。
try { UUID uuid = UUID.fromString(uuidString); // 我们的正常逻辑。 return uuid; // 我们返回我们的类型,在这个例子中,解析器会认为类型已经正确解析,并继续。 // UUID 在由字符串生成时,可能会抛出异常,因此我们捕获这个异常,并将其包装成 CommandSyntaxException 类型。 // 创建时会带有环境,告诉 Brigadier,根据这个环境来告诉玩家,命令在哪里解析失败了。 // 尽管应该使用正常的 create 方法。 throw new SimpleCommandExceptionType(Text.literal(ex.getMessage())).createWithContext(reader); }
ArgumentType
完成了,你的客户端却会拒绝解析参数并抛出错误。这是因为服务器会告诉客户端这是什么参数类型。而客户端不会解析它不知道的参数类型。要解决这个问题,我们需要在 ModInitializer
中注册一个 ArgumentSerializer
。对于更加复杂的参数类型,你可能还需要创建自己的 ArgumentSerializer
。
ArgumentTypeRegistry.registerArgumentType(new Identifier("tutorial", "uuid"), UuidArgumentType.class, ConstantArgumentSerializer.of(UuidArgumentType::uuid)); // 这个参数会创建 ArgumentType。
参数类型的完整代码会是这样:
- UuidArgumentType.java
- import com.mojang.brigadier.StringReader;
- import com.mojang.brigadier.arguments.ArgumentType;
- import com.mojang.brigadier.context.CommandContext;
- import com.mojang.brigadier.exceptions.CommandSyntaxException;
- import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
- import net.minecraft.text.Text;
- import net.minecraft.util.SystemUtil;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.UUID;
- /**
- * Represents an ArgumentType that will return a UUID.
- */
- public class UuidArgumentType implements ArgumentType<UUID> {
- public static UuidArgumentType uuid() {
- return new UuidArgumentType();
- }
- // Note that you should assume the CommandSource wrapped inside of the CommandContext will always be a generic type.
- // If you need to access the ServerCommandSource make sure you verify the source is a server command source before casting.
- return context.getArgument(name, UUID.class);
- }
- private static final Collection<String> EXAMPLES = SystemUtil.consume(new ArrayList<>(), list -> {
- list.add("765e5d33-c991-454f-8775-b6a7a394c097"); // i509VCB: Username The_1_gamers
- list.add("069a79f4-44e9-4726-a5be-fca90e38aaf5"); // Notch
- list.add("61699b2e-d327-4a01-9f1e-0ea8c3f06bc6"); // Dinnerbone
- });
- @Override
- int argBeginning = reader.getCursor(); // The starting position of the cursor is at the beginning of the argument.
- if (!reader.canRead()) {
- reader.skip();
- }
- // Now we check the contents of the argument till either we hit the end of the
- // command line (when ''canRead'' becomes false)
- // Otherwise we go till reach reach a space, which signifies the next argument
- while (reader.canRead() && reader.peek() != ' ') { // peek provides the character at the current cursor position.
- reader.skip(); // Tells the StringReader to move it's cursor to the next position.
- }
- // Now we substring the specific part we want to see using the starting cursor
- // position and the ends where the next argument starts.
- try {
- UUID uuid = UUID.fromString(uuidString); // Now our actual logic.
- return uuid;
- // And we return our type, in this case the parser will consider this
- // argument to have parsed properly and then move on.
- // UUIDs can throw an exception when made by a string, so we catch the exception
- // and repackage it into a CommandSyntaxException type.
- // Create with context tells Brigadier to supply some context to tell the user
- // where the command failed at.
- // Though normal create method could be used.
- throw new SimpleCommandExceptionType(Text.literal(ex.getMessage())).createWithContext(reader);
- }
- }
- @Override
- public Collection<String> getExamples() {
- // Brigadier has support to show examples for what the argument should look like,
- // this should contain a Collection of only the argument this type will return.
- // This is mainly used to calculate ambiguous commands which share the exact same
- return EXAMPLES;
- }
- }