Blocks & Block States
Blocks are the fundamental building units of Minecraft. Each block has properties called "states" that define its appearance and behavior. Understanding block properties lets you detect changes, modify block behavior on the fly, and build dynamic world systems.
Understanding Block States
Block states are the dynamic properties that make blocks behave differently - a door can be open or closed, crops grow through different ages, logs face different directions. When you modify a block state, you're changing how that block looks and behaves without changing what type of block it is.
Why this matters: Instead of replacing blocks entirely, you can adjust their properties. This is more efficient and lets you create interactive systems.
How It Works
Every block has a "permutation" - a combination of its type plus all its current property values. When you want to change a block's appearance or behavior:
- Get the block at a location
- Get its current permutation (type + properties)
- Create a new permutation with modified properties
- Apply it back to the block
import { world } from "@minecraft/server";
// Get a block at a specific location
const block = world.getDimension("overworld").getBlock({ x: 0, y: 64, z: 0 });
// Read a block property (get its current value)
const age = block.permutation.getProperty("age");
console.log("Crop age:", age);
// Modify a block property (create new permutation with changed property)
const newPermutation = block.permutation.withProperty("age", 7); // Fully grown
block.setPermutation(newPermutation);
// Chain multiple properties (modify multiple at once)
const rotatedOpen = block.permutation
.withProperty("rotation", 1)
.withProperty("open", true);
block.setPermutation(rotatedOpen);
Why use permutations? Because changing one property resets others if you're not careful. A permutation tracks the full state, so you can modify one property while preserving the others.
Common Block Properties
| Property | Type | Example Values | Use Case |
|---|---|---|---|
facing_direction |
Number | 0-5 (down, up, north, south, west, east) | Stairs, logs, furnaces facing different directions |
rotation |
Number | 0-15 | Wall banners, map facing direction |
powered |
Boolean | true/false | Redstone blocks, repeaters, comparators |
open |
Boolean | true/false | Doors, gates, trapdoors |
age |
Number | 0-7 (crops), varies by plant | Crop growth stages, tree growth |
Reading vs. Modifying
// **Reading** - get current state (doesn't change anything)
const currentAge = block.permutation.getProperty("age");
const isOpen = block.permutation.getProperty("open");
// **Modifying** - change state (affects the block in world)
const grown = block.permutation.withProperty("age", 7);
block.setPermutation(grown); // Now the block displays fully grown
// **Combining** - modify multiple properties at once
const doorState = block.permutation
.withProperty("open", true)
.withProperty("facing_direction", 2); // Facing north
block.setPermutation(doorState);
Practical Examples
// Auto-harvest wheat at full growth
world.afterEvents.blockBreak.subscribe((event) => {
const block = event.brokenBlockPermutation;
if (block.type.id.includes("wheat")) {
const age = block.getProperty("age");
// Only drop seeds if it was fully grown (age 7)
if (age === 7) {
console.log("Full wheat harvested - drop seeds");
}
}
});
// Open doors near a redstone signal
world.afterEvents.blockBreak.subscribe((event) => {
const block = event.block;
if (block.typeId === "minecraft:redstone_block") {
// Find nearby doors and open them
const nearbyBlocks = block.dimension.getBlocks(
{ x: block.location.x - 5, y: block.location.y - 5, z: block.location.z - 5 },
{ x: block.location.x + 5, y: block.location.y + 5, z: block.location.z + 5 }
);
for (const nearbyBlock of nearbyBlocks) {
if (nearbyBlock.typeId === "minecraft:oak_door") {
const opened = nearbyBlock.permutation.withProperty("open", true);
nearbyBlock.setPermutation(opened);
}
}
}
});
// Cycle through crop ages (useful for testing or farming automation)
function advanceCropGrowth(block) {
const currentAge = block.permutation.getProperty("age") || 0;
const maxAge = 7; // Most crops go 0-7
if (currentAge < maxAge) {
const nextStage = block.permutation.withProperty("age", currentAge + 1);
block.setPermutation(nextStage);
return true;
}
return false; // Already fully grown
}
Best Practices
- Always get the full permutation before modifying - don't assume other properties won't change
- Check property exists before reading - not all blocks have all properties
- Use in block events - detect changes with
blockBreakandblockPlaceevents - Test interactively - use creative mode to see what properties blocks have
- Chain properties carefully - order matters when you're applying multiple changes