4.9 KiB
Model API
🌐 Languages: English | Українська
In general, it is designed to mimic the latest version.
Intentional deviations
None (for now).
Former deviations
Texture references are no longer assumed to be the same as 7.10 locations.
Instead, they are resolved from assets/namespace/textures like modern
does. This also means you can now use any texture in your ISBRH, and
GTNHLib will inject it into the block atlas. Please use this power responsibly.
Resource packs can now replace most blocks, similarly to modern. Note that this primarily works on blocks with ISBRHS - if the block has a TESR registered in code, that should result in both the model and the TESR rendering.
Examples
BlockColor
Use to color to TintIndex
Example: using BlockColor register
BlockColor.registerBlockColors(new IBlockColor() {
@Override
public int colorMultiplier(IBlockAccess world, int x, int y, int z, int tintIndex) {
// Return red for main layer, green for secondary
return tintIndex == 0 ? 0xFF0000 : 0x00FF00;
}
@Override
public int colorMultiplier(ItemStack stack, int tintIndex) {
// Return blue for main layer, yellow for secondary
return tintIndex == 0 ? 0x0000FF : 0xFFFF00;
}
}, ModBlocks.MY_CUSTOM_BLOCK);
Example: implement IBlockColor directly in a block
public class BlockTestTint extends Block implements IBlockColor {
public BlockTestTint() {
super(Material.wood);
}
@Override
public int colorMultiplier(IBlockAccess world, int x, int y, int z, int tintIndex) {
return switch(tintIndex) {
case 0 -> 0xFF0000; // red
case 1 -> 0x00FF00; // green
case 2 -> 0x0000FF; // blue
case 3 -> 0xFFFF00; // yellow
case 4 -> 0xFF00FF; // magenta
case 5 -> 0x00FFFF; // cyan
default -> 0xFFFFFF; // white
};
}
@Override
public int colorMultiplier(ItemStack stack, int tintIndex) {
return colorMultiplier(null, 0, 0, 0, tintIndex);
}
}
BlockState Api
Instead of relying on 4-bit metadata, model selection can resolved from full block state data via registered BlockProperty.
This allows:
- Unlimited logical states (no 16-meta restriction)
- Model variants based on TileEntity data
- ItemStack-aware state resolution
- Dynamic rendering behavior
BlockState resolution works in three steps:
- A
BlockPropertyis registered to a block (and optionally its item). - The property provides values from:
- World + TileEntity
- ItemStack
- The JsonModel loader resolves model variants using those property values.
1.Creating a BlockProperty
Example: Direction property backed by TileEntity.
DirectionBlockProperty property = new DirectionBlockProperty() {
@Override
public String getName() {
return "facing";
}
@Override
public boolean hasTrait(BlockPropertyTrait trait) {
return switch (trait) {
case SupportsWorld, WorldMutable, StackMutable, SupportsStacks -> true;
default -> false;
};
}
@Override
public ForgeDirection getValue(IBlockAccess world, int x, int y, int z) {
TileEntity te = world.getTileEntity(x, y, z);
if (te instanceof TileTestTintMul tile) {
return tile.getFacing();
}
return ForgeDirection.NORTH;
}
@Override
public void setValue(World world, int x, int y, int z, ForgeDirection value) {
TileEntity te = world.getTileEntity(x, y, z);
if (te instanceof TileTestTintMul tile) {
tile.setFacing(value);
}
}
@Override
public ForgeDirection getValue(ItemStack stack) {
return ForgeDirection.NORTH;
}
};
2.Registering the Property
BlockPropertyRegistry.registerProperty(block, property); BlockPropertyRegistry.registerProperty(Item.getItemFromBlock(block), property);
You must register:
- On the block (world state)
- On the item (inventory rendering)
3.Defining blockstate JSON
Example:
{
"variants": {
"facing=north": { "model": "modid:block/machine_north" },
"facing=south": { "model": "modid:block/machine_south" },
"facing=west": { "model": "modid:block/machine_west" },
"facing=east": { "model": "modid:block/machine_east" }
}
}
The loader will:
- Query property.getValue(...)
- Build a state string like: facing=north
- Resolve the correct model variant
Supported Traits
BlockPropertyTrait controls where the property works:
SupportsWorld→ usable in world renderingSupportsStacks→ usable in item renderingWorldMutable→ value can be changed in worldStackMutable→ value can be changed in ItemStack
Only implement the traits you need.
TODO
- Add smooth shading to ModelISBRH.
- Add face culling to models.
- Implement UV locking.