User Tools

Site Tools


zh_cn:tutorial:colorprovider

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
zh_cn:tutorial:colorprovider [2019/12/19 05:48] lightcolourzh_cn:tutorial:colorprovider [2025/04/01 12:11] (current) solidblock
Line 1: Line 1:
-====== 提供颜色 ======+====== 颜色提供器 ======
  
-有没有想过,草和树叶如何根据生物群而改变色调,或者皮革甲如何具有看似无限的颜色模式? 颜色提供者见面后者让您根据位置NBT块状态等属性和项目模型纹理进行色调着色。+有没有想过,草和树叶如何根据生物群而改变色调的?皮革甲如何具有看似无限的颜色模式?答案是**颜色提供器**这个以允许你根据位置NBT、方块状态等属性为方或物品的模型纹理设置色调或者着色。
  
-=== 现有例子 === +===== 原版例子 ===== 
-首先,现有的哪些原版内容使用颜色提供程序? 一些示例包括:+首先,现有的哪些原版内容使用颜色提供?一些示例包括:
    *草    *草
    *树叶    *树叶
-   *皮革盔甲垂死+   *皮革盔甲着色
    *红石线    *红石线
-   *瓜类,甘蔗和睡莲等植物 +   *西甘蔗和睡莲等植物 
-   *+   *
  
-颜色提供程序功能强大,但是Mojang选择对混凝土羊毛和玻璃等有色块坚持使用单独的纹理。 此时的主要用例是针对生物群落阴影对现有纹理的细微调整,例如带尖的彩色末端。+颜色提供功能强大,但是 Mojang 选择对混凝土羊毛和玻璃等有色块坚持使用单独的纹理。此时的主要用例是针对生物群系的方,以及对现有纹理的细微调整,例如箭的彩色末端。
  
-颜色提供程序背后的概念很简单。 您向其注册块或项目,并在渲染该块或项目的模型时,颜色提供程序将色调调整应用于纹理的每一层。 两提供都可以访问模型的层,这意味着您可以分别对模型的每个部分进行色调设置,皮革盔甲和带尖头的就是这种情况。 当您只想更改几个像素而不是整个纹理时,这很有用。+颜色提供背后的概念很简单。你为之注册和物品,并在渲染该块或物品的模型时,颜色提供器对纹理的每一层应用色调调整。两提供都可以访问模型的层,这意味着您可以分别对模型的每个部分进行色调设置,皮革盔甲和箭就是这种情况。当您只想更改几个像素而不是整个纹理时,这很有用。
  
-请记住,提供颜色是客户端机制。 确保将与其相关的所有代码放入客户端初始化程序中。+请记住,颜色提供器是客户端机制。确保将与其相关的所有代码放入客户端初始化中。
  
-===== 注册方块 Color Provider ===== +===== 方块颜色提供器 ===== 
-要将块注册到块颜色提供程序,您需要使用Fabric的''ColorProviderRegistry''。 此类中有一个''BLOCK和''ITEM''提供程序的实例,可以调用register。 register方法接受您的颜色提供程序的一个实例,以及要使用该提供程序进行着色的每个块的变量。 + 
-<code java [enable_line_numbers="false"]> +要将块注册到块颜色提供,您需要使用 Fabric 的 ''ColorProviderRegistry''。此类中有一个 ''BLOCK'' 和 ''ITEM'' 提供的实例,可以调用 ''register''''register'' 方法接受颜色提供的一个实例,以及要使用该提供进行着色的每个块的变量。 
-ColorProviderRegistry.BLOCK.register(new BlockColorProvider() { + 
-        @Override +首先,先在 ''TutoriaoBlocks'' 类创建方块,关于如何创建方块,见 [[blocks]]: 
- public int getColor(BlockState stateExtendedBlockView worldBlockPos pos, int layer+<code java TutorialBlocks.class> 
- return 0x3495eb+public final class TutorialBlocks { 
- } +  [...
-}, MY_BLOCK);+ 
 +  // 1.21.2 之前: 
 +  public static final Block COLOR_BLOCK = register("color_block", new Block(AbstractBlock.Settings.create())); 
 +   
 +  // 1.21.2 及之后: 
 +  public static final Block COLOR_BLOCK = register("color_block"Block::newAbstractBlock.Settings.create()); 
 +}
 </code> </code>
  
-我们在这里所做的只是说:"Hi,''MY_BLOCK''应被着色为0x3495eb",这是蓝色。 您具有BlockState,World和BlockPos上下文,这是您可以根据生物群系或位置更改颜色的方式。 最后的int是图层; 每人都要求一种颜色,但是在这种情况下,我们总是返回蓝色。+简单添加方块状态文件:
  
-模型也很重要这里的主提示是//您需要//为要色调的模型的每个部分定义一个tintindex。 要查看此示例,请查看''leaves.json'',这是用于原版叶的基本模型。 这是用于我们块的模型: +<code javascript src/main/resources/assets/tutorial/blockstates/color_block.json> 
-<code json [enable_line_numbers="false"]>+
 +  "variants":
 +    "":
 +      "model": "tutorial:block/color_block" 
 +    } 
 +  } 
 +
 +</code> 
 + 
 +在你的 ''ClientModInitializer'': 
 +<code java ExampleModClient.java> 
 +@Environment(EnvType.CLIENT) 
 +public class ExampleModClient implements ClientModInitializer { 
 +  @Override 
 +  public void onInitializeClient() { 
 +    // ... 
 + 
 +    ColorProviderRegistry.BLOCK.register((state, view, pos, tintIndex) -> 0x3495eb, TutorialBlocks.COLOR_BLOCK); 
 +  } 
 +
 +</code> 
 + 
 +如果还没有的话,记得在你的 [[documentation:fabric_mod_json|fabric.mod.json]] 中注册: 
 +<code javascript> 
 +
 +  // ... 
 +  "entrypoints":
 +    // ... 
 +    "client":
 +      "net.fabricmc.example.ExampleModClient" 
 +    ] 
 +  }, 
 +  // ... 
 +
 +</code> 
 + 
 +然后创建带有 //tintindex// 的模型:模型也很重要这里注意的,你//一定要//为模型的每你需要着色的部分定义tintindex。要查看这个的,请参考 ''leaves.json'',这是原版使用的基本模型。这是我们使用的模型: 
 + 
 +<code javascript src/main/resources/assets/tutorial/models/block/color_block.json>
 { {
   "parent": "block/block",   "parent": "block/block",
Line 40: Line 84:
   },   },
   "elements": [   "elements": [
-    {   "from": [ 0, 0, 0 ],+    { "from": [ 0, 0, 0 ],
       "to": [ 16, 16, 16 ],       "to": [ 16, 16, 16 ],
       "faces": {       "faces": {
Line 54: Line 98:
 } }
 </code> </code>
-在这种情况下,我们添加了一个单一的tintindex,它会出现在`layer`参数(第0层)中。 
  
-这是最终结果-请注意,原始模型使用了''white_concrete''纹理:+在这个实例里面,我们添加了单一的 tintindex,出现在 ''tintIndex'' 参数中(着色索引 0)。事实上,方块可以直接继承 ''minecraft:block/leaves'' 模型,因为也使用的带有 tintindex 的方块。所以可以将上面的模型替换为: 
 +<code javascript src/main/resources/assets/tutorial/models/block/color_block.json> 
 +
 +  "parent": "block/leaves", 
 +  "textures":
 +    "all": "block/white_concrete" 
 +  } 
 +
 +</code> 
 + 
 +> **注意:**方块颜色是有缓存的,如果提供了随时间改变的颜色,这个改变不会直接生效,除非附近有方块更新。 
 + 
 +这是最终结果——请注意,原始模型使用了 ''white_concrete''(白色混凝土)纹理(下图使用了 imgur 图床)
 {{https://i.imgur.com/fZLS10g.png}} {{https://i.imgur.com/fZLS10g.png}}
  
-===== 注颜色提供物品 ===== + 
-项目相似;区别提供的上下。 您无需访问状态世界位置,而可以访问''ItemStack''。 +===== 带有颜色提供器的方块实体 ===== 
-<code java [enable_line_numbers="false"]+ 
-ColorProviderRegistry.ITEM.register((itemStacklayer) -> +如果你需要在颜色提供器中访问 ''BlockEntity'' 数据,你需要实现来自 ''RenderDataBlockEntity'' 的 ''getRenderData()'' 方法,这是 Fabric API 的接口,不过[[interface_injection|入]]到的 ''BlockEntity'' 中。如果使用的是旧版本,尝试实现 ''RenderAttachmentBlockEntity'' 并返回你需要的数据。 
- return 0x3495eb; + 
-}, COLORED_ITEM);+这是因为方块可以在单独的线程渲染,所以直接访问数据并不安全。而且,如果使用 ''getBlockState'' 查询方块,你无法查看整个世界——确保你只查询当前位置的 ±2 方块范围内的位置。 
 + 
 +在这个例子中,我们创建一个 ''ColorBlock'' 类和 ''ColorBlockEntity'' 类,并连接方块与方块实体(更多信息见[[blockentity|方块实体]]教程)。 
 + 
 +<code java ColorBlock.java> 
 +public class ColorBlock extends BlockWithEntity { 
 +  public ColorBlock(Settings settings) { 
 +    super(settings); 
 +  } 
 + 
 +  @Override 
 +  protected MapCodec<? extends ColorBlock> getCodec() { 
 +    return createCodec(ColorBlock::new); 
 +  } 
 + 
 +  @Nullable 
 +  @Override 
 +  public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { 
 +    return new ColorBlockEntity(pos, state); 
 +  } 
 + 
 +  // 自从 1.21.4 开始,不再需要这个方法,因为所有方块实体都默认使用方块模型。 
 +  @Override 
 +  protected BlockRenderType getRenderType(BlockState state) { 
 +    return BlockRenderType.MODEL; 
 +  } 
 +
 +</code> 
 + 
 +<code java ColorBlockEntity.java> 
 +public class ColorBlockEntity extends BlockEntity { 
 +  public int color = 0x3495eb; 
 +   
 +  public ColorBlockEntity(BlockPos pos, BlockState state) { 
 +    super(TutorialBlockEntityTypes.COLOR_BLOCK, pos, state); 
 +  } 
 +   
 +  // 以下两个方块指定了颜色数据的序列化。 
 + 
 +  @Override 
 +  protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { 
 +    super.readNbt(nbt, registryLookup); 
 +     
 +    // 对于 1.21.5 之前的版本,请直接使用 nbt.getInt("color"); 
 +    color = nbt.getInt("color", 0); 
 +     
 +    // 当数据通过“/data”命令修改,或者放置了有“block_entity_data”组件的物品时, 
 +    // 需要同步更新。 
 +    if (world != null) { 
 +      world.updateListeners(pos, getCachedState(), getCachedState(), 0); 
 +    } 
 +  } 
 + 
 +  @Override 
 +  protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { 
 +    super.writeNbt(nbt, registryLookup); 
 +    nbt.putInt("color", color); 
 +  } 
 + 
 +  @Nullable 
 +  @Override 
 +  public Packet<ClientPlayPacketListener> toUpdatePacket() { 
 +    return BlockEntityUpdateS2CPacket.create(this); 
 +  } 
 + 
 +  @Override 
 +  public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registryLookup) { 
 +    return createNbt(registryLookup); 
 +  } 
 + 
 +  @Override 
 +  public @Nullable Object getRenderData() { 
 +    // 这是来自 `RenderDataBlockEntity` 类的方法。 
 +    return color; 
 +  } 
 +
 +</code> 
 + 
 +在 ''TutorialBlocks'' 类中,将 ''new Block'' 替换为 ''new ColorBlock'': 
 +<code java> 
 +  // 1.21.2 之前: 
 +  public static final ColorBlock COLOR_BLOCK = register("color_block", new ColorBlock(AbstractBlock.Settings.create())); 
 +   
 +  // 1.21.2 及之后: 
 +  public static final Block COLOR_BLOCK = register("color_block", ColorBlock::new, AbstractBlock.Settings.create()); 
 +</code> 
 + 
 +在 ''TutorialBlockEntityTypes'' 类中: 
 +<code java> 
 +  public static final BlockEntityType<ColorBlockEntity> COLOR_BLOCK = register("color_block", 
 +      BlockEntityType.Builder.create(ColorBlockEntity::new, TutorialBlocks.COLOR_BLOCK).build()); 
 +</code> 
 + 
 +> 不要忘了在你的模组初始化器中,静态加载 ''TutorialBlocks'' 和 ''TutorialBlockEntityTypes'' 类。 
 + 
 +现在我们修改 ''onUseWithItem'' 方法,这样颜色会在我们使用染料与方块接触时改变: 
 +<code java ColorBlock.java> 
 +public class ColorBlock extends BlockWithEntity { 
 +  [...] 
 +   
 +  @Override 
 +  protected ActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { 
 +    if (stack.getItem() instanceof DyeItem dyeItem) { 
 +      if (world.getBlockEntity(pos) instanceof ColorBlockEntity colorBlockEntity) { 
 +        final int newColor = dyeItem.getColor().getEntityColor(); 
 +        final int originalColor = colorBlockEntity.color; 
 +        colorBlockEntity.color = ColorHelper.average(newColor, originalColor); 
 +        stack.decrementUnlessCreative(1, player); 
 +        colorBlockEntity.markDirty(); 
 +        world.updateListeners(pos, state, state, 0); 
 +      } 
 +    } 
 +    return super.onUseWithItem(stack, state, world, pos, player, hand, hit); 
 +  } 
 +   
 +  [...] 
 +
 +</code> 
 + 
 +最后,修改颜色提供器以使用渲染数据。我们调用 ''FabricBlockView.getBlockEntityRenderData'' 以确保线程安全和数据连贯。 
 +<code java ExampleModClient.java> 
 +@Environment(EnvType.CLIENT) 
 +public class ExampleModClient implements ClientModInitializer { 
 +  [...] 
 +  @Override 
 +  public void onInitializeClient() { 
 +    [...] 
 + 
 +    ColorProviderRegistry.BLOCK.register((state, view, pos, tintIndex) -> view != null && view.getBlockEntityRenderData(pos) instanceof Integer integer ? integer : 0x3495eb, TutorialBlocks.COLOR_BLOCK); 
 +  } 
 +
 +</code> 
 + 
 +搞定!现在你可以检查下面这些是否都正常起作用: 
 +  * 使用染料交互,颜色应该改变。 
 +  * 通过 ''/data'' 命令修改颜色时,颜色应该改变。 
 +  * 按下 ''Ctrl'' 同时拾取(按下鼠标中键)并放置方块,应该显示为预期的颜色。 
 +  * 离开世界重进,颜色应该保留。 
 + 
 +===== 自定义物品着色(1.21.4 及之后) ===== 
 +从 1.21.4 开始,物品的着色是由物品模型映射指定的。原版提供了几种常见的着色来源的类型,参见 [[https://zh.minecraft.wiki/w/物品模型映射|Minecraft Wiki]]。这个例子中,我们需要直接指定物品的颜色,因此可以将物品模型映射像这样写: 
 +<code javascript /resources/assets/tutorial/items/color_block.json> 
 +
 +  "model":
 +    "type": "model", 
 +    "model": "tutorial:block/color_block", 
 +    "tints":
 +      { 
 +        "type": "constant", 
 +        "value": 3446251 
 +      } 
 +    ] 
 +  } 
 +
 +</code> 
 + 
 +如果需要指定自定义的着色来源,可以使用原版提供的 ''TintResourceTypes.//ID_MAPPER//.put(...)'' 进行注册。注意是在客户端环境下完成的。注册时使用的 ID 将是面的物品模型映射中的 ''%%"tints"%%'' 中的 ''%%"type"%%'' 的值。 
 + 
 +> 如果着色不生效,检查使用的模型中的 tintindex 的值,应该与物品模型映射中的 ''%%"tints"%%'' 列表中的元素下标对应例如,如果 tintindex 为 2,表示将使用物品模型映射中的第三个着色来源。 
 + 
 +===== 物品颜色提供器(1.21.4 之前) ===== 
 +在 1.21.3 以及之前的版本,物品的颜色提供器也是可通过 Fabric API 注册的。与方块不同,物品的颜色提供器提供的上下文不访问状态世界位置,而访问 ''ItemStack'' 
 + 
 +物品模型可以直接继承使用 tintindex 的方块模型: 
 + 
 +首先,物品需要一个直接继承方块模型的物品模型: 
 +<code javascript /resources/assets/tutorial/models/item/color_block.json> 
 +
 +  "parent": "tutorial:block/color_block" 
 +
 +</code
 + 
 +然后,再在客户端环境中,注册颜色提供器。 
 + 
 +<code java ExampleModClient.java> 
 +@Environment(EnvType.CLIENT) 
 +public class ExampleModClient implements ClientModInitializer { 
 +  @Override 
 +  public void onInitializeClient() { 
 +    // ... 
 + 
 +    ColorProviderRegistry.ITEM.register((stacktintIndex) -> 0x3495eb, TutorialBlocks.COLOR_BLOCK); 
 +  } 
 +}
 </code> </code>
  
-将色相相同的方块库存量项目+会以像方块那样的方你物品栏中物品提供色相
  
-=== 性 === +===== 制 ===== 
-使用颜色提供程序的一个关键问题是项目提供程序中缺少上下文。 这就是为什么原版草不会根据您站立的位置改变存货颜色的原因。 为了实现诸如块的颜色变体(混凝土玻璃羊毛等)之类的东西,建议您为每个版本简单地提供单独的纹理。+使用颜色提供的一个关键问题是物品的提供中缺少上下文。这就是为什么原版草不会根据您站立的位置改变物品栏中的颜色的原因。为了实现诸如块的颜色变体(混凝土玻璃羊毛等)之类的东西,建议您为每个版本简单地提供单独的纹理。
zh_cn/tutorial/colorprovider.1576734501.txt.gz · Last modified: 2019/12/19 05:48 by lightcolour