# Model API 🌐 **Languages:** [English](models.md) | [Українська](models_uk.md) 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:
1. A `BlockProperty` is registered to a block (and optionally its item).
2. The property provides values from:
- World + TileEntity
- ItemStack
3. 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 rendering
- `SupportsStacks` → usable in item rendering
- `WorldMutable` → value can be changed in world
- `StackMutable` → 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.