Block Architecture & State System
Blocks form the static and dynamic foundation of Minecraft worlds. In Pumpkin, block handling is cleanly bifurcated into two distinct layers:
- Static Data Layer (
pumpkin-data): Compile-time generated metadata including numeric block IDs, block state IDs, hardness, blast resistance, light emission, opacity, collision shapes, and block state properties generated bypumpkin-codegen. - Dynamic Behavior Layer (
pumpkin::block): Server-side behavioral hooks—such as opening containers, toggling redstone signals, growing crops, breaking triggers, and collision effects—handled via theBlockBehaviourtrait.
Static Blocks vs. Interactive Behaviors
Because Minecraft contains thousands of block state combinations, Pumpkin avoids allocating runtime behavior structs for simple, non-interactive blocks:
| Category | Description | Examples | Runtime Behavior Required? |
|---|---|---|---|
| Static Blocks | Rigid solid voxels without interactive logic or custom physics | stone, dirt, cobblestone, bedrock, obsidian | No — Placement, breaking times, and tool requirements are handled entirely by pumpkin-data. |
| Interactive Blocks | Blocks triggered by right-clicks or tool actions | door, trapdoor, lever, button, crafting_table | Yes — Implements BlockBehaviour::normal_use or use_with_item. |
| Collision Blocks | Blocks that modify entity movement or apply forces | honey_block, slime_block, soul_sand, powder_snow | Yes — Implements on_entity_collision or on_landed_upon. |
| Redstone Components | Power sources, conductors, and logic gates | redstone_wire, repeater, comparator, observer | Yes — Implements emits_redstone_power and on_neighbor_update. |
| Block Entities | Blocks with persistent, serialized custom states | chest, furnace, sign, decorated_pot, spawner | Yes — Implements create_block_entity and links a BlockEntity. |
Block IDs, States, and Properties
Minecraft distinguishes between a Block type and a specific Block State:
1. BlockId and BlockStateId
BlockId: An identifier representing a base block type (e.g.,minecraft:oak_door).BlockStateId: A 16-bit integer representing a unique combination of block properties (e.g.,minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]).
In Pumpkin, block data is looked up from precomputed lookup tables in pumpkin-data:
use pumpkin_data::Block;
use pumpkin_data::BlockStateId;
// Access static properties directly from generated data
let door_block = Block::OAK_DOOR;
let default_state_id: BlockStateId = door_block.default_state_id;
let hardness = door_block.hardness;
let blast_resistance = door_block.blast_resistance;
let is_air = door_block.is_air;2. Generated State Property Helpers
Rather than parsing raw strings or bitmasks manually, pumpkin-codegen generates strongly typed property helpers in pumpkin_data::block_properties:
use pumpkin_data::block_properties::{DoorLikeProperties, DoubleBlockHalf, Facing};
// Read typed properties from a numeric BlockStateId
let is_open = DoorLikeProperties::open(state_id);
let half = DoorLikeProperties::half(state_id);
let facing = DoorLikeProperties::facing(state_id);
// Generate a new BlockStateId with mutated properties
let toggled_state_id = DoorLikeProperties::with_open(state_id, !is_open);Physics, Bounding Boxes & Raycasting
Pumpkin calculates collision and raycasting bounding boxes directly using pre-baked shapes in pumpkin-data:
- Solid Collisions: During physics ticks, an entity's axis-aligned bounding box (AABB) is tested against surrounding block collision voxels.
- Raycasting: When a player targets a block to place or break, client raycasts are validated against the server-side block outline shapes.
- Custom Movement Hooks: Blocks like slime blocks or honey blocks override vertical rebound or horizontal velocity:
bounce_entity_after_fall: Dampens fall damage and multiplies rebound velocity.stop_vertical_movement_after_fall: Zeros fall velocity upon contact.
Block Entities (Tile Entities)
When a block must store arbitrary dynamic data that cannot fit into standard block state bits (such as container inventories, custom sign text, brewing timers, or mob spawner delays), it uses a Block Entity:
| Component | Responsibility | Implementation File |
|---|---|---|
BlockEntity Trait | Defines NBT serialization (to_nbt, from_nbt) and tick execution | crates/pumpkin/src/block/entities/ |
create_block_entity | Hook in BlockBehaviour called when placing the block | Attached to relevant block behaviors |
| Chunk Entity Storage | Manages active block entities and coordinates within chunk sections | crates/pumpkin-world |
The Block Registry & Dispatch System
Block interaction events are routed through the central BlockRegistry in crates/pumpkin/src/block/registry.rs:
- Registration: At server initialization, all behavior structs are registered into the
BlockManager. - Mapping: The manager maps numeric
BlockIdkeys to thread-safe behavior instances (Arc<dyn BlockBehaviour>). - Dispatch: When the network layer receives block action packets (such as
CUseItemOnor block dig packets), the server looks up the behavior in $O(1)$ time and invokes the relevant hook.
Next Steps
To implement a new interactive block behavior, continue to the practical guide:
- Adding a Block: Complete walk-through of declaring attributes, implementing interaction hooks, creating block entities, and registering behaviors.