Blocks
Declaring a block
BlockHandle block = mod.content().block("copper_bricks", BlockDefinition.builder()
.strength(2.0f, 6.0f)
.requiresCorrectTool()
.sound(BlockSound.COPPER)
.item(ItemDefinition.builder().creativeTab(CreativeTab.BUILDING_BLOCKS).build())
.build());
| Builder method | Meaning |
|---|---|
strength(hardness, explosionResistance) | Hardness and explosion resistance |
requiresCorrectTool() | Drops only when mined with the right tool (tool tags come from a data pack or addToTag) |
sound(BlockSound) | STONE, WOOD, GRAVEL, GRASS, METAL, GLASS, WOOL, SAND, COPPER, AMETHYST |
lightLevel(int) / lightLevel(state -> …) | Light level, or a light level per state |
friction(float) | Slipperiness |
noCollision(), noOcclusion() | No collision; does not block light or view |
behavior(BlockBehavior) | Behavior callbacks |
item(ItemDefinition) / noItem() | Definition of the block item with the same ID / no block item |
properties(...), facesPlayerWhenPlaced(...) | State properties |
randomTicks() | Receive random ticks (onRandomTick) |
blockEntity(BlockEntityDefinition) | Block entity. See Block entities and menus |
Pick the creative tab from CreativeTab: BUILDING_BLOCKS, COLORED_BLOCKS, NATURAL_BLOCKS, FUNCTIONAL_BLOCKS, REDSTONE_BLOCKS, TOOLS_AND_UTILITIES, COMBAT, FOOD_AND_DRINKS, INGREDIENTS, SPAWN_EGGS. The item is added at the end of the tab. A mod's own tab is described in Tags and creative tabs.
Behavior callbacks
Every method of BlockBehavior has a default implementation, so override only what you need.
| Method | Called when |
|---|---|
onUse(BlockUse use) | A player uses the block (use.world(), use.pos(), use.player()) |
onSteppedOn(world, pos, entity) | An entity steps on the block |
onPlaced(world, pos, placer) | The block is placed |
onRandomTick(world, pos) | Random tick (needs randomTicks()) |
onNeighborChanged(world, pos) | A neighboring block changes |
If onUse returns PASS, the game's default behavior applies.
Block state properties
static final BlockProperty.DirectionProperty FACING = BlockProperty.horizontalFacing("facing");
static final BlockProperty.BooleanProperty POWERED = BlockProperty.bool("powered");
BlockDefinition.builder()
.facesPlayerWhenPlaced(FACING) // face the player when placed
.properties(POWERED)
.randomTicks() // BlockBehavior.onRandomTick
.build();
world.stateAt(pos).get(POWERED);
world.setProperty(pos, POWERED, true);
- Property kinds:
bool,integer(min, max),horizontalFacing,direction,choice(name, values...). Change the default withwithDefault(...). - Default state: The default values of the properties form the default state.
- Blockstate file: Pick models in the vanilla format, such as
"facing=north,powered=false". - Reading vanilla blocks: You can also read the state of a game block when the property has the same name and type (for example
facingon a furnace). Check first withstateAt(pos).has(property). - Trying to change a property the block does not have throws
IllegalArgumentException.
Named properties
static final BlockProperty.ChoiceProperty COLOR = BlockProperty.choice("color", "red", "green", "blue"); // the first value is the default
- In a blockstate file, write it as
color=blue. - Game properties with the same name (
halfon stairs,axison logs, and so on) can also be read and changed as strings. - A value that is not allowed throws
IllegalArgumentException.
Per-state light
static final BlockProperty.BooleanProperty LIT = BlockProperty.bool("lit");
mod.content().block("lamp", BlockDefinition.builder()
.properties(COLOR, LIT)
.lightLevel(state -> state.get(LIT) ? 15 : 0) // light level per state
.behavior(new BlockBehavior() {
@Override
public InteractionResult onUse(BlockUse use) {
if (!use.world().isClientSide()) {
use.world().setProperty(use.pos(), LIT, true);
}
return InteractionResult.SUCCESS;
}
})
.build());
lightLevel(state -> …) is computed once per state when the block is created. Check it with WorldView.emittedLight(pos). There is no separate light provider API.
Shape and collision
For blocks that are not a full cube, such as slabs, posts, and pipes, give the outline with shape. The unit is pixels, and one block spans 0..16 on each axis. This matches from/to of block model elements.
// Half-height: entities stand at y + 0.5, and the outline is half a block too
mod.content().block("stone_step", BlockDefinition.builder()
.shape(BlockShape.box(0, 0, 0, 16, 8, 16))
.build());
// A base and a post, plus a handle rotated to the facing direction
static final BlockProperty.DirectionProperty FACING = BlockProperty.horizontalFacing("facing");
static final BlockShape HANDLE = BlockShape.box(6, 10, 0, 10, 12, 4); // shape when facing north
mod.content().block("lever_post", BlockDefinition.builder()
.properties(FACING)
.facesPlayerWhenPlaced(FACING)
.shape(state -> BlockShape.box(0, 0, 0, 16, 2, 16)
.or(BlockShape.box(6, 2, 6, 10, 16, 10))
.or(HANDLE.facing(state.get(FACING))))
.collisionShape(BlockShape.box(0, 0, 0, 16, 2, 16).or(BlockShape.box(6, 2, 6, 10, 16, 10)))
.build());
| Method | Meaning |
|---|---|
shape(BlockShape), shape(state -> …) | The outline the player aims at, which is also the collision shape |
collisionShape(…) | When only the collision differs |
BlockShape.box(…), or(…) | One box; combine shapes |
BlockShape.facing(direction) | Rotates a north-facing shape to that direction |
BlockShape.FULL, BlockShape.EMPTY | A full block; no shape |
- The game computes the per-state shape once per state at startup. If the function throws or returns
null, the result isPOLY-CONTENT-006. - The game hides only the neighboring faces that the shape covers. The block model does not change, so draw the model to match the shape. For a slab, use
"parent": "minecraft:block/slab". - With
noCollision(), the block does not collide regardless ofcollisionShape.
Blockstate file example
{
"variants": {
"lit=false": {"model": "my_mod:block/lamp_off"},
"lit=true": {"model": "my_mod:block/lamp_on"}
}
}
The states of mod blocks also go into the game's block state ID table. That is why changes to mod blocks can be sent to the client (this fixed a disconnect problem in early versions).