1. 模型染色

考虑下列几个情况:

  • 原版的草方块、草丛、树叶、蕨、水、甘蔗等方块在不同的生物群系中有不同的颜色。
  • 红石线的颜色会随着红石信号的强度变化而改变其“深浅”。
  • 可以通过西瓜梗和南瓜梗的颜色来判断它们熟没熟。
  • 原版皮革盔甲可以染色。
  • 原版药水瓶依靠药水的“颜色”令玩家能根据其外观区分种类。类似地,原版刷怪蛋也依靠颜色区分种类。

以及两个比较极端的,不是原版的情况:

  • 格雷科技(GregTech)的几千个有完全相同模型和纹理,惟独颜色不同的物品。
  • 匠魂(Tinkers' Construct)自身拥有十余种不同“材质”的工具零件,相同种类的零件基本共用一种模型,和格雷科技一样,亦是仅有颜色上的差别。这些零件的模型最终会被“组装”成完整的工具模型。

这些奇奇怪怪的案例有一个共同特点:“给模型染色,而不是把基本相同的模型重复几百遍”。原版 Minecraft 正好有这么一个允许你给模型染色的机制。

1.1. tintIndex

支持染色的方块模型中应当有 tintIndex 这个属性。原版所有用到这个属性的模型中,这个属性的值都是 0。下面给出一个改造后的原版 minecraft:block/cube 模型以说明 tintIndex 属性应当如何使用:

{
    "parent": "block/block",
    "elements": [
        {  
            "from": [ 0, 0, 0 ],
            "to": [ 16, 16, 16 ],
            "faces": {
                "down":  { "texture": "#down", "tintindex": 0, "cullface": "down" },
                "up":    { "texture": "#up", "tintindex": 0, "cullface": "up" },
                "north": { "texture": "#north", "tintindex": 0, "cullface": "north" },
                "south": { "texture": "#south", "tintindex": 0, "cullface": "south" },
                "west":  { "texture": "#west", "tintindex": 0, "cullface": "west" },
                "east":  { "texture": "#east", "tintindex": 0, "cullface": "east" }
            }
        }
    ]
}

虽然 Minecraft Wiki 上“模型”一文提到了这个属性,但它提供的信息并不多。
此外,对于物品模型,只要最终使用的物品模型直接或间接继承自 item/generated 就能支持染色,不需要特别的操作。

1.2. 方块模型染色

import net.minecraft.client.renderer.color.IBlockColor;

public final class MyBlockTinter implements IBlockColor {
    @Override
    public int colorMultiplier(IBlockState state, @Nullable IBlockAccess worldIn, @Nullable BlockPos pos, int tintIndex) {
        // 在这里返回的颜色代码将决定最终方块模型的“颜色”。这里使用 RGB。
        // 第四个参数即是上文中提到的 `tintIndex` 属性的值。
        return 0;
    }
}

正确实现 IBlockColor 后,注册它即可。Forge 提供了一个事件,允许我们在 Minecraft 自己加载完它自用的 IBlockColor 后立即注册我们自己的 IBlockColor

@SubscribeEvent
public static void blockColors(ColorHandlerEvent.Block event) {
    // 第二个参数代表“所有需要使用此 IBlockColor 的物品”,是一个 var-arg Block。
    // 有鉴于第一个参数是一个只有一个方法的接口,我们也可以直接在这里使用 lambda 表达式。
    event.getBlockColors().registerBlockColorHandler(new MyBlockTinter(), block1, block2, block3, ...);
}

1.3. 物品模型染色

import net.minecraft.client.renderer.color.IItemColor;

public final class MyItemTinter implements IItemColor {
    @Override
    public int colorMultiplier(ItemStack stack, int tintIndex) {
        // 在这里返回的颜色代码将决定最终物品模型的“颜色”。这里使用 RGB。
        // 第二个参数即是上文中提到的 `tintIndex` 属性的值。
        return 0;
    }
}

正确实现 IItemColor 后,注册它即可。和 IBlockColor 一样,Forge 提供了一个事件,允许我们在 Minecraft 自己加载完它自用的 IItemColor 后立即注册我们自己的 IItemColor。相比

@SubscribeEvent
public static void itemColors(ColorHandlerEvent.Item event) {
    // 第二个参数代表“所有需要使用此 IItemColor 的物品”,是一个 var-arg Item。
    // 有鉴于第一个参数是一个只有一个方法的接口,我们也可以直接在这里使用 lambda 表达式。
    event.getItemColors().registerItemColorHandler(new MyItemTinter(), item1, item2, item3, ...);

    // 出于某些原因,你还可以在这里拿到之前的 `BlockColors`。在某些时候这个玩意会很有用。
    BlockColors blockColorHandler = event.getBlockColors();
}