Many blocks and items in vanilla change their texture color depending on where they are, such as grass. Models support specifying “tint indices” on faces, which are integers that can then be handled by
IItemColors. See the wiki for information on how tint indices are defined in vanilla models.
Both of these are single-method interfaces.
IBlockColor takes an
IBlockState, an (nullable)
ILightReader, and a (nullable)
IItemColor takes an
ItemStack. Both of them take a parameter
tintindex, which is the tint index of the face being colored. Both of them return an
int, a color multiplier. This
int is treated as 4 unsigned bytes, alpha, red, green, and blue, in that order, from most significant byte to least. For each pixel in the tinted face, the value of each color channel is
(int)((float)base * multiplier / 255), where
base is the original value for the channel, and
multiplier is the associated byte from the color multiplier. Note that blocks do not use the alpha channel. For example, the grass texture, untinted, looks white and gray. The
IItemColor for grass return color multipliers with low red and blue components, but high alpha and green components, (at least in warm biomes) so when the multiplication is performed, the green is brought out and the red/blue diminished.
If an item inherits from the
builtin/generated model, each layer (“layer0”, “layer1”, etc.) has a tint index corresponding to its layer index.
IBlockColors need to be registered to the
BlockColors instance of the game.
BlockColors can be acquired through
Minecraft.getMinecraft().getBlockColors(), and an
IBlockColor can be registered by
BlockColors::registerBlockColorHandler. Note that this does not cause the
ItemBlock for the given block to be colored.
ItemBlocks are items and need to colored with an
IItemColors need to be registered to the
ItemColors instance of the game.
ItemColors can be acquired through
Minecraft.getMinecraft().getItemColors(), and an
IItemColor can be registered by
ItemColors::registerItemColorHandler. This method is overloaded to also take
Blocks, which simply registers the color handler for the item
Item.getItemFromBlock(block) (i.e. the block’s
This registration must be done client-side, in the initialization phase.