tutorial:colorprovider
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| tutorial:colorprovider [2024/08/26 07:11] – solidblock | tutorial:colorprovider [2025/04/01 12:10] (current) – solidblock | ||
|---|---|---|---|
| Line 18: | Line 18: | ||
| ===== Block Color Provider ===== | ===== Block Color Provider ===== | ||
| - | To register a block to the block color provider, you'll need to use Fabric' | + | To register a block to the block color provider, you'll need to use Fabric' |
| At first, we create the block in '' | At first, we create the block in '' | ||
| Line 24: | Line 24: | ||
| public final class TutorialBlocks { | public final class TutorialBlocks { | ||
| [...] | [...] | ||
| + | // Before 1.21.2 | ||
| public static final Block COLOR_BLOCK = register(" | public static final Block COLOR_BLOCK = register(" | ||
| + | | ||
| + | // 1.21.2 and after: | ||
| + | public static final Block COLOR_BLOCK = register(" | ||
| } | } | ||
| </ | </ | ||
| Line 67: | Line 70: | ||
| </ | </ | ||
| - | Then we create the block model with // | + | Then we create the block model with // |
| - | + | ||
| - | The model is also important: the main note here is that you are // | + | |
| <code javascript src/ | <code javascript src/ | ||
| { | { | ||
| Line 93: | Line 94: | ||
| </ | </ | ||
| - | In this instance, we're adding a single tintindex, which is what would appear in the '' | + | In this instance, we're adding a single tintindex, which is what would appear in the '' |
| <code javascript src/ | <code javascript src/ | ||
| { | { | ||
| Line 108: | Line 109: | ||
| {{https:// | {{https:// | ||
| - | If you need to access '' | + | ===== Block Entity with Color Provider ===== |
| + | |||
| + | If you need to access '' | ||
| + | |||
| + | This is because blocks can be rendered on separate threads, so accessing the data directly is not safe. Additionally, | ||
| + | |||
| + | In this case, we create a '' | ||
| + | |||
| + | <code java ColorBlock.java> | ||
| + | public class ColorBlock extends BlockWithEntity { | ||
| + | public ColorBlock(Settings settings) { | ||
| + | super(settings); | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | protected MapCodec<? | ||
| + | return createCodec(ColorBlock:: | ||
| + | } | ||
| + | |||
| + | @Nullable | ||
| + | @Override | ||
| + | public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { | ||
| + | return new ColorBlockEntity(pos, | ||
| + | } | ||
| + | |||
| + | // Since 1.21.4, this method is not required anymore, because all block entities use their block model by default. | ||
| + | @Override | ||
| + | protected BlockRenderType getRenderType(BlockState state) { | ||
| + | return BlockRenderType.MODEL; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code java ColorBlockEntity.java> | ||
| + | public class ColorBlockEntity extends BlockEntity { | ||
| + | public int color = 0x3495eb; | ||
| + | |||
| + | public ColorBlockEntity(BlockPos pos, BlockState state) { | ||
| + | super(TutorialBlockEntityTypes.COLOR_BLOCK, | ||
| + | } | ||
| + | |||
| + | // The following two methods specify serialization of color data. | ||
| + | |||
| + | @Override | ||
| + | protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { | ||
| + | super.readNbt(nbt, | ||
| + | |||
| + | // For versions before 1.21.5, please directly use nbt.getInt(" | ||
| + | color = nbt.getInt(" | ||
| + | |||
| + | // When the data is modified through "/ | ||
| + | // or placed by an item with " | ||
| + | // the render color will be updated. | ||
| + | if (world != null) { | ||
| + | world.updateListeners(pos, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { | ||
| + | super.writeNbt(nbt, | ||
| + | nbt.putInt(" | ||
| + | } | ||
| + | |||
| + | @Nullable | ||
| + | @Override | ||
| + | public Packet< | ||
| + | return BlockEntityUpdateS2CPacket.create(this); | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registryLookup) { | ||
| + | return createNbt(registryLookup); | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public @Nullable Object getRenderData() { | ||
| + | // this is the method from `RenderDataBlockEntity` class. | ||
| + | return color; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | In the '' | ||
| + | <code java> | ||
| + | // Before 1.21.2: | ||
| + | public static final ColorBlock COLOR_BLOCK = register(" | ||
| + | |||
| + | // Since 1.21.2: | ||
| + | public static final Block COLOR_BLOCK = register(" | ||
| + | </ | ||
| + | |||
| + | In the '' | ||
| + | <code java> | ||
| + | public static final BlockEntityType< | ||
| + | BlockEntityType.Builder.create(ColorBlockEntity:: | ||
| + | </ | ||
| + | |||
| + | Now we modify '' | ||
| + | <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, | ||
| + | stack.decrementUnlessCreative(1, | ||
| + | colorBlockEntity.markDirty(); | ||
| + | world.updateListeners(pos, | ||
| + | } | ||
| + | } | ||
| + | return super.onUseWithItem(stack, | ||
| + | } | ||
| + | |||
| + | [...] | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Finally, modify the color provider to use the render data. We call '' | ||
| + | <code java ExampleModClient.java> | ||
| + | @Environment(EnvType.CLIENT) | ||
| + | public class ExampleModClient implements ClientModInitializer { | ||
| + | [...] | ||
| + | @Override | ||
| + | public void onInitializeClient() { | ||
| + | [...] | ||
| + | |||
| + | ColorProviderRegistry.BLOCK.register((state, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Now done! Then you can check whether the following work correctly: | ||
| + | * When you interact the block with a dye, the color should change. | ||
| + | * When you modify the color through ''/ | ||
| + | * When you pick (press mouse wheel) the block with '' | ||
| + | * When you leave the world and re-enter, the color should be kept. | ||
| + | |||
| + | ===== Custom item tint (1.21.4 and after) ===== | ||
| + | Since 1.21.4 开始, tints of items are defined in item models definitions. Some common tint source types are provided in vanilla, see [[https:// | ||
| + | <code javascript / | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | If you need to specify a custom tint source, you can register with '' | ||
| + | |||
| + | > If the tint does not work, check the value of tintindex in the model, which should be consistent with the element subscript in the '' | ||
| - | ===== Item Color Provider ===== | + | In version 1.21.3 and before, item model providers |
| - | Items are similar; the difference is the context provided. Instead | + | |
| - | For item models, we can directly inherite the block model, which uses tintindex: | + | For item models, we can directly inherite the block model that uses tintindex: |
| <code javascript src/ | <code javascript src/ | ||
| { | { | ||
tutorial/colorprovider.1724656281.txt.gz · Last modified: 2024/08/26 07:11 by solidblock