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
zh_cn:tutorial:command_argument_types [2024/04/15 07:14] solidblockzh_cn:tutorial:command_argument_types [2024/04/15 07:24] (current) solidblock
Line 167: Line 167:
 } }
 </file> </file>
 +
 +===== 指定建议 =====
 +
 +很多参数类型都支持建议。不像在注册过程中定义的自定义建议,当没有自定义建议时,始终会应用这些建议。建议是在客户端中计算的。例如,''BlockPosArgumentType'' 可能会建议客户端的准星目标的位置,''EntityArgumentType'' 可能会建议准星目标实体的准确 UUID。
 +
 +关于如何提供建议,请参见[[command suggestions|命令建议]]。在这个例子中,我们会建议服务器中的所有玩家的 UUID,以及当前客户端的准星目标实体。
 +
 +<code java>
 +  @Override
 +  public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
 +    final String remaining = builder.getRemaining();
 +    if (context.getSource() instanceof FabricClientCommandSource clientCommandSource) {
 +      if (clientCommandSource.getClient().crosshairTarget instanceof EntityHitResult entityHitResult) {
 +        final UUID uuid = entityHitResult.getEntity().getUuid();
 +        if (CommandSource.shouldSuggest(remaining, uuid.toString())) {
 +          builder.suggest(uuid.toString());
 +        }
 +      }
 +      return CommandSource.suggestMatching(Collections2.transform(clientCommandSource.getClient().getNetworkHandler().getPlayerUuids(), UUID::toString), builder);
 +    }
 +
 +    if (context.getSource() instanceof ServerCommandSource source) {
 +      return CommandSource.suggestMatching(Lists.transform(source.getServer().getPlayerManager().getPlayerList(), Entity::getUuidAsString), builder);
 +    }
 +    
 +    return builder.buildFuture();
 +  }
 +</code>
 +
 +===== 自定义参数序列化 ======
 +在上面的例子中,UUID 是简单的。如果参数是复杂的,如何让它能够正确地被客户端理解呢?这就是 ''ArgumentSerializer'' 有用的地方。
 +
 +''ArgumentSerializer'' 有两个泛型参数:
 +  * ''ArgumentType''
 +  * ''ArgumentSerializer.ArgumentTypeProperties<A>'',,其中 ''A'' 是第一个类型参数。通常是一个不可变的对象(可以是记录),包含参数类型基本的信息(不包含 ''CommandRegistryAccess'')。一些情况下,如果 ''ArgumentType'' 是不可变的、不包含 ''CommandRegistryAccess'',那么它自己就可以直接继承 ''ArgumentSerializer.ArgumentTypeProperties<A>''
 +
 +在这个例子中,我们创建一个新的参数类型,包含一个布尔值和一个整数。这个例子中,需要 ''CommandRegistryAccess''
 +
 +<code java>
 +public record ExampleArgumentType(CommandRegistryAccess commandRegistryAccess, boolean booleanValue, int intValue) implements ArgumentType<String> {
 +  @Override
 +  public String parse(StringReader reader) throws CommandSyntaxException {
 +    ...
 +  }
 +  
 +  public static class Serializer implements ArgumentSerializer<ExampleArgumentType, Serializer.Properties> {
 +    @Override
 +    public void writePacket(Properties properties, PacketByteBuf buf) {
 +      // 将基本的属性写到数据包中,需要确保所有的参数都以适当方式存储在数据包中。
 +      buf.writeBoolean(properties.booleanValue).writeInt(properties.intValue);
 +    }
 +
 +    @Override
 +    public Properties fromPacket(PacketByteBuf buf) {
 +      // 从数据包中读取信息。返回的是 ''ArgumentSerializer.ArgumentTypeProperties'' 而不是 ''ArgumentType''
 +      return new Properties(buf.readBoolean(), buf.readInt());
 +    }
 +
 +    @Override
 +    public void writeJson(Properties properties, JsonObject json) {
 +      // 以 JSON 的形式呈现参数类型。
 +      json.addProperty("booleanValue", properties.booleanValue);
 +      json.addProperty("intValue", properties.intValue);
 +    }
 +
 +    @Override
 +    public Properties getArgumentTypeProperties(ExampleArgumentType argumentType) {
 +      return new Properties(argumentType.booleanValue, argumentType.intValue);
 +    }
 +
 +    public record Properties(boolean booleanValue, int intValue) implements ArgumentTypeProperties<ExampleArgumentType> {
 +      @Override
 +      public ExampleArgumentType createType(CommandRegistryAccess commandRegistryAccess) {
 +        // 只有在此方法中会提供 ''CommandRegistryAccess''
 +        // 会创建需要 ''CommandRegistryAccess'' 的参数类型。
 +        return new ExampleArgumentType(commandRegistryAccess, booleanValue, intValue);
 +      }
 +
 +      @Override
 +      public ArgumentSerializer<ExampleArgumentType, Serializer.Properties> getSerializer() {
 +        // 不要在这里创建新的 ''Serializer'' 对象。
 +        return Serializer.this;
 +      }
 +    }
 +  }
 +}
 +</code>
 +
 +现在你可以像这样注册:
 +<code java>
 +ArgumentTypeRegistry.registerArgumentType(new Identifier("tutorial", "example"), ExampleArgumentType.class, new ExampleArgumentType.Serializer());
 +</code>
 +
 +==== 另一种可能的定义序列化的方式 ====
 +
 +如果参数不需要 ''CommandRegistryAccess'',那么它自己就可以继承 ''ArgumentSerializer.ArgumentTypeProperties''
 +
 +<code java>
 +public record ExampleArgumentType(boolean booleanValue, int intValue) implements ArgumentType<String>, ArgumentSerializer.ArgumentTypeProperties<ExampleArgumentType> {
 +  @Override
 +  public String parse(StringReader reader) throws CommandSyntaxException {
 +    ...
 +  }
 +
 +  @Override
 +  public ExampleArgumentType createType(CommandRegistryAccess commandRegistryAccess) {
 +    return this;
 +  }
 +
 +  @Override
 +  public ArgumentSerializer<ExampleArgumentType, ?> getSerializer() {
 +    // 这里总是返回同一个对象,以避免无法序列化。
 +    return Serializer.INSTANCE;
 +  }
 +
 +  public static class Serializer implements ArgumentSerializer<ExampleArgumentType, ExampleArgumentType> {
 +    public static final Serializer INSTANCE = new Serializer();
 +    private Serializer() {}
 +  
 +    @Override
 +    public void writePacket(ExampleArgumentType properties, PacketByteBuf buf) {
 +      buf.writeBoolean(properties.booleanValue).writeInt(properties.intValue);
 +    }
 +
 +    @Override
 +    public ExampleArgumentType fromPacket(PacketByteBuf buf) {
 +      return new ExampleArgumentType(buf.readBoolean(), buf.readInt());
 +    }
 +
 +    @Override
 +    public void writeJson(ExampleArgumentType properties, JsonObject json) {
 +      json.addProperty("booleanValue", properties.booleanValue);
 +      json.addProperty("intValue", properties.intValue);
 +    }
 +
 +    @Override
 +    public ExampleArgumentType getArgumentTypeProperties(ExampleArgumentType argumentType) {
 +      return argumentType;
 +    }
 +  }
 +}
 +</code>
 +
 +现在你可以像这样注册:
 +<code java>
 +ArgumentTypeRegistry.registerArgumentType(new Identifier("tutorial", "example"), ExampleArgumentType.class, ExampleArgumentType.Serializer.INSTANCE);
 +</code>
  
zh_cn/tutorial/command_argument_types.txt · Last modified: 2024/04/15 07:24 by solidblock