Block Interactions & Events
Interact with blocks, detect changes, and create custom block behaviors. Block events power everything from restricted mining to auto-farms to interactive structures.
Understanding Block Events
Block events fire when blocks change - placed, broken, exploded, or when their properties are modified. You can react to these events to:
- Prevent certain blocks from being mined or placed
- Auto-replace blocks (e.g., stone → custom texture)
- Build structures automatically when a player places a marker block
- Track farming/mining activities
- Trigger redstone contraptions
Key concept: Block events tell you what changed (location, player, block type, block state), and you can react by modifying the world or preventing the action.
Why use block events instead of checking every tick? Polling every block's state is inefficient. Events only fire when something actually changes, so you only pay CPU when it matters.
Block Breaking & Placement
blockBreak fires AFTER a block is broken (too late to prevent), but you can detect what was broken and react. blockPlace fires AFTER placement, allowing you to auto-build structures or validate placement.
import { world } from "@minecraft/server";
// **Block Break** - fires when player breaks a block
// Note: afterEvents means the break already happened - you can't cancel it
// (Use beforeEvents if available to prevent breaking)
world.afterEvents.blockBreak.subscribe((event) => {
const block = event.brokenBlockPermutation; // What was broken (includes properties)
const player = event.player; // Who broke it
const location = event.block.location; // Where it was
// **Track mining** (useful for economy or achievements)
if (block.type.id.includes("ore")) {
console.log(`${player.nameTag} mined ore at ${location.x}, ${location.y}, ${location.z}`);
// Could give them money, XP, or track stats
}
// **Prevent breaking important blocks** (though this runs after break)
// Better approach: restore the block immediately
if (block.type.id === "minecraft:obsidian") {
player.sendMessage("§cYou cannot break obsidian!");
// Restore the block
const dimension = event.block.dimension;
dimension.setBlockType(location, "minecraft:obsidian");
}
});
// **Block Place** - fires when player places a block
// Use this to: trigger structures, validate placement, track building
world.afterEvents.blockPlace.subscribe((event) => {
const block = event.block; // Block that was placed
const player = event.player; // Who placed it
const location = block.location;
player.sendMessage(`§aPlaced ${block.typeId}`);
// **Auto-build on placement** - when player places special marker block, build structure
// Example: place emerald block to spawn a pillar
if (block.typeId === "minecraft:emerald_block") {
createPillar(block.location);
}
});
// **Helper function** - builds a pillar of gold 5 blocks tall
function createPillar(location) {
const dim = world.getDimension("overworld");
// Build from 1 block above the emerald, up to 5 blocks
for (let i = 1; i <= 5; i++) {
const blockAbove = dim.getBlock({
x: location.x,
y: location.y + i,
z: location.z
});
blockAbove.setType("minecraft:gold_block");
}
}
Explosion & Redstone Events
Detect explosions and redstone activation to trigger custom logic - great for maps, puzzle mechanics, or logging.
// **Explosion event** - triggers when TNT, creeper, or other explosion happens
world.afterEvents.explosion.subscribe((event) => {
const explosionCenter = event.source; // Vector of explosion origin
const affectedBlocks = event.getImpactedBlocks(); // Array of blocks affected
console.log(`Explosion at ${explosionCenter.x}, ${explosionCenter.y}, ${explosionCenter.z}`);
console.log(`${affectedBlocks.length} blocks affected`);
// **Use case: prevent griefing** - detect explosions near important structures
// const sanctuaryRadius = 20;
// if (distance(explosionCenter, SPAWN_POINT) < sanctuaryRadius) {
// // Explosion too close to spawn - could punish the player or disable explosions
// }
});
// **Redstone block activation** - fires when redstone circuit activates/powers a block
world.afterEvents.blockExplode.subscribe((event) => {
const block = event.block; // Block that was affected by redstone
// **Detect specific redstone interactions**
if (block.typeId === "minecraft:redstone_block") {
console.log("Redstone activated!");
// Could trigger custom behavior
// - Open doors
// - Give players items
// - Teleport players
// - Start event timers
}
if (block.typeId === "minecraft:command_block") {
console.log("Command block received redstone signal");
}
});
Block Properties
Block properties (or "states") change how a block appears and behaves without changing its type. A door can be open/closed, crops can be age 0-7, redstone can be powered/unpowered.
// Get a specific block
const block = world.getDimension("overworld").getBlock({ x: 0, y: 64, z: 0 });
// **Read all properties** for a block
const permutation = block.permutation; // Current state (type + all properties)
const properties = permutation.getAllProperties();
// Log every property this block has
for (const prop of properties) {
console.log(`${prop.name}: ${prop.value}`);
}
// **Read specific properties**
const isOpen = block.permutation.getProperty("open"); // true/false for doors
const age = block.permutation.getProperty("age"); // 0-7 for crops
const powered = block.permutation.getProperty("powered"); // true/false for redstone
const facing = block.permutation.getProperty("facing_direction"); // 0-5 for direction
// **Modify properties** - create a new permutation with changed properties
// Why new permutation? Because properties are immutable - you can't change one in place
const newPermutation = block.permutation
.withProperty("open", true) // Open the door
.withProperty("age", 7) // Fully grow crop
.withProperty("powered", true); // Power the redstone
// Apply the new permutation back to the block
block.setPermutation(newPermutation);
// **Common use case: open a door when player enters pressure plate**
// const door = world.getDimension("overworld").getBlock(doorLocation);
// const opened = door.permutation.withProperty("open", true);
// door.setPermutation(opened);
Block Ticking
Monitor blocks over time to detect changes or apply continuous effects. Better than entityTick since you only check specific blocks instead of everything in the world.
// Track active ticking blocks so we can stop them later
const tickingBlocks = new Map();
function monitorBlockChanges(location, checkInterval = 100) {
const dim = world.getDimension("overworld");
// Create an interval that checks this specific block
const interval = setInterval(() => {
const block = dim.getBlock(location);
if (!block) return; // Block doesn't exist anymore
// **Check block properties and react**
if (block.typeId === "minecraft:furnace") {
// Check if furnace is currently cooking
const lit = block.permutation.getProperty("lit"); // true if furnace is running
console.log(`Furnace at ${location.x},${location.y},${location.z} is ${lit ? "cooking" : "idle"}`);
}
if (block.typeId === "minecraft:cauldron") {
// Check water level
const level = block.permutation.getProperty("fill_level");
if (level === 0) {
// Cauldron is empty - could notify admin, trigger event, etc.
}
}
}, checkInterval); // Run every N milliseconds
// Store the interval ID so we can stop it later
tickingBlocks.set(JSON.stringify(location), interval);
return interval;
}
// **Stop monitoring a block** - clean up the interval
function stopMonitoringBlock(location) {
const key = JSON.stringify(location);
const interval = tickingBlocks.get(key);
if (interval) {
clearInterval(interval);
tickingBlocks.delete(key);
}
}
// Usage:
// monitorBlockChanges({ x: 0, y: 64, z: 0 }, 100); // Check every 100ms
Sculpting & Custom Shapes
Generate structures programmatically by calculating which blocks to fill. Useful for arena setup, loot generation, or procedural dungeons.
// **Create a sphere of blocks** - useful for arenas, beacons, or obstacles
function createSphere(center, radius, blockType) {
const dim = world.getDimension("overworld");
// Loop through all coordinates in a cube that bounds the sphere
for (let x = center.x - radius; x <= center.x + radius; x++) {
for (let y = center.y - radius; y <= center.y + radius; y++) {
for (let z = center.z - radius; z <= center.z + radius; z++) {
// Calculate distance from this block to the sphere's center
// Using Pythagorean theorem: distance = sqrt(dx² + dy² + dz²)
const distance = Math.sqrt(
Math.pow(x - center.x, 2) +
Math.pow(y - center.y, 2) +
Math.pow(z - center.z, 2)
);
// Only place blocks within the radius (forms a sphere shape)
if (distance <= radius) {
const block = dim.getBlock({ x, y, z });
block.setType(blockType);
}
}
}
}
}
// **Create a cylinder** - good for towers or columns
function createCylinder(center, height, radius, blockType) {
const dim = world.getDimension("overworld");
for (let y = center.y; y < center.y + height; y++) {
for (let x = center.x - radius; x <= center.x + radius; x++) {
for (let z = center.z - radius; z <= center.z + radius; z++) {
// Only check distance on X/Z plane (ignore Y for height)
const distance = Math.sqrt(
Math.pow(x - center.x, 2) +
Math.pow(z - center.z, 2)
);
if (distance <= radius) {
const block = dim.getBlock({ x, y, z });
block.setType(blockType);
}
}
}
}
}
// Usage
createSphere({ x: 0, y: 64, z: 0 }, 10, "minecraft:diamond_block"); // 20 block diameter sphere
createCylinder({ x: 100, y: 64, z: 100 }, 20, 5, "minecraft:stone"); // Tower 20 high, 10 wide
Crop Detection & Farming
Detect when crops are harvested and respond - great for farming systems, achievements, or economy rewards.
world.afterEvents.blockBreak.subscribe((event) => {
const block = event.brokenBlockPermutation; // Block that was broken (includes properties)
const player = event.player; // Who broke it
// **Detect crop harvesting** - check if broken block is wheat/carrot/potato
if (block.type.id.includes("wheat") || block.type.id.includes("carrot") || block.type.id.includes("potato")) {
// Crops have an "age" property: 0 = newly planted, 7 = fully grown
const age = block.getProperty("age");
if (age === 7) {
// **Fully grown crop** - give bonus rewards or XP
console.log("Fully grown crop harvested!");
player.sendMessage("§aYou harvested a fully grown crop!");
// Could reward the player:
// playerData.farmingXP += 50;
// playerData.crops_harvested += 1;
} else {
// **Premature harvest** - crop wasn't ready, could penalize or warn
console.log(`Premature harvest - crop age ${age}/7`);
player.sendMessage(`§cCrop not ready! Age: ${age}/7`);
// Could reduce reward or lock them out:
// return; // Don't give reward
}
}
// **Other crop types**
if (block.type.id === "minecraft:sugar_cane") {
// Sugar cane doesn't have age, just check if it exists
console.log("Sugar cane harvested");
}
});