🇬🇧 English
🇬🇧 English
Appearance
🇬🇧 English
🇬🇧 English
Appearance
This page is written for version:
1.21
This page is written for version:
1.21
A block state is a piece of data attached to a singular block in the Minecraft world containing information on the block in the form of properties - some examples of properties vanilla stores in block states:
You can probably see why they are useful - they avoid the need to store NBT data in a block entity - reducing the world size, and preventing TPS issues!
Blockstate definitions are found in the assets/<mod id here>/blockstates
folder.
Minecraft has some custom classes already that allow you quickly create certain types of blocks - this example goes through the creation of a block with the axis
property by creating a "Condensed Oak Log" block.
The vanilla PillarBlock
class allows the block to be placed in the X, Y or Z axis.
public static final Block CONDENSED_OAK_LOG = register(
new PillarBlock(
AbstractBlock.Settings.create()
.sounds(BlockSoundGroup.WOOD)
), "condensed_oak_log", true
);
ItemGroupEvents.modifyEntriesEvent(ModItems.CUSTOM_ITEM_GROUP_KEY).register((itemGroup) -> {
itemGroup.add(ModBlocks.CONDENSED_DIRT.asItem());
});
Pillar blocks have two textures, top and side - they use the block/cube_column
model.
As always, with all block textures, the texture files can be found in assets/<mod id here>/textures/block
Since the pillar block has two positions, horizontal and vertical, we'll need to make two separate model files:
condensed_oak_log_horizontal.json
which extends the block/cube_column_horizontal
model.condensed_oak_log.json
which extends the block/cube_column
model.An example of the condensed_oak_log_horizontal.json
file:
{
"parent": "block/cube_column_horizontal",
"textures": {
"end": "fabric-docs-reference:block/condensed_oak_log_top",
"side": "fabric-docs-reference:block/condensed_oak_log"
}
}
INFO
Remember, blockstate files can be found in the assets/<mod id here>/blockstates
folder, the name of the blockstate file should match the block ID used when registering your block in the ModBlocks
class. For instance, if the block ID is condensed_oak_log
, the file should be named condensed_oak_log.json
.
For a more in-depth look at all the modifiers available in the blockstate files, check out the Minecraft Wiki - Models (Block States) page.
Next, we need to create a blockstate file. The blockstate file is where the magic happens—pillar blocks have three axes, so we'll use specific models for the following situations:
axis=x
- When the block is placed along the X axis, we will rotate the model to face the positive X direction.axis=y
- When the block is placed along the Y axis, we will use the normal vertical model.axis=z
- When the block is placed along the Z axis, we will rotate the model to face the positive X direction.{
"variants": {
"axis=x": {
"model": "mod_id:block/condensed_oak_log_horizontal",
"x": 90,
"y": 90
},
"axis=y": {
"model": "mod_id:block/condensed_oak_log"
},
"axis=z": {
"model": "mod_id:block/condensed_oak_log_horizontal",
"x": 90
}
}
}
As always, you'll need to create a translation for your block, and an item model which parents either of the two models.
Custom block states are great if your block has unique properties - sometimes you may find that your block can re-use vanilla properties.
This example will create a unique boolean property called activated
- when a player right-clicks on the block, the block will go from activated=false
to activated=true
- changing its texture accordingly.
Firstly, you'll need to create the property itself - since this is a boolean, we'll use the BooleanProperty.of
method.
public class PrismarineLampBlock extends Block {
public static final BooleanProperty ACTIVATED = BooleanProperty.of("activated");
}
Next, we have to append the property to the blockstate manager in the appendProperties
method. You'll need to override the method to access the builder:
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(ACTIVATED);
}
You'll also have to set a default state for the activated
property in the constructor of your custom block.
public PrismarineLampBlock(Settings settings) {
super(settings);
// Set the default state of the block to be deactivated.
setDefaultState(getDefaultState().with(ACTIVATED, false));
}
WARNING
Don't forget to register your block using the custom class instead of Block
!
This example flips the boolean activated
property when the player interacts with the block. We can override the onUse
method for this:
@Override
protected ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) {
if (!player.getAbilities().allowModifyWorld) {
// Skip if the player isn't allowed to modify the world.
return ActionResult.PASS;
} else {
// Get the current value of the "activated" property
boolean activated = state.get(ACTIVATED);
// Flip the value of activated and save the new blockstate.
world.setBlockState(pos, state.with(ACTIVATED, !activated));
// Play a click sound to emphasise the interaction.
world.playSound(player, pos, SoundEvents.BLOCK_COMPARATOR_CLICK, SoundCategory.BLOCKS, 1.0F, 1.0F);
return ActionResult.SUCCESS;
}
}
Before creating the blockstate file, you will need to provide textures for both the activated and deactivated states of the block, as well as the block model.
Use your knowledge of block models to create two models for the block: one for the activated state and one for the deactivated state. Once you've done that, you can begin creating the blockstate file.
Since you created a new property, you will need to update the blockstate file for the block to account for that property.
If you have multiple properties on a block, you'll need to account for all possible combinations. For example, activated
and axis
would lead to 6 combinations (two possible values for activated
and three possible values for axis
).
Since this block only has two possible variants, as it only has one property (activated
), the blockstate JSON will look something like this:
{
"variants": {
"activated=false": {
"model": "fabric-docs-reference:block/prismarine_lamp"
},
"activated=true": {
"model": "fabric-docs-reference:block/prismarine_lamp_on"
}
}
}
Since the example block is a lamp, we also need to make it emit light when the activated
property is true. This can be done through the block settings passed to the constructor when registering the block.
You can use the luminance
method to set the light level emitted by the block, we can create a static method in the PrismarineLampBlock
class to return the light level based on the activated
property, and pass it as a method reference to the luminance
method:
public static int getLuminance(BlockState currentBlockState) {
// Get the value of the "activated" property.
boolean activated = currentBlockState.get(PrismarineLampBlock.ACTIVATED);
// Return a light level if activated = true
return activated ? 15 : 0;
}
public static final Block PRISMARINE_LAMP = register(
new PrismarineLampBlock(
AbstractBlock.Settings.create()
.sounds(BlockSoundGroup.LANTERN)
.luminance(PrismarineLampBlock::getLuminance)
), "prismarine_lamp", true
);
Once you've completed everything, the final result should look something like the following: