Skip to content

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:

  1. 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 by pumpkin-codegen.
  2. 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 the BlockBehaviour trait.

Static Blocks vs. Interactive Behaviors

Because Minecraft contains thousands of block state combinations, Pumpkin avoids allocating runtime behavior structs for simple, non-interactive blocks:

CategoryDescriptionExamplesRuntime Behavior Required?
Static BlocksRigid solid voxels without interactive logic or custom physicsstone, dirt, cobblestone, bedrock, obsidianNo — Placement, breaking times, and tool requirements are handled entirely by pumpkin-data.
Interactive BlocksBlocks triggered by right-clicks or tool actionsdoor, trapdoor, lever, button, crafting_tableYes — Implements BlockBehaviour::normal_use or use_with_item.
Collision BlocksBlocks that modify entity movement or apply forceshoney_block, slime_block, soul_sand, powder_snowYes — Implements on_entity_collision or on_landed_upon.
Redstone ComponentsPower sources, conductors, and logic gatesredstone_wire, repeater, comparator, observerYes — Implements emits_redstone_power and on_neighbor_update.
Block EntitiesBlocks with persistent, serialized custom stateschest, furnace, sign, decorated_pot, spawnerYes — 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:

rust
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:

rust
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:

ComponentResponsibilityImplementation File
BlockEntity TraitDefines NBT serialization (to_nbt, from_nbt) and tick executioncrates/pumpkin/src/block/entities/
create_block_entityHook in BlockBehaviour called when placing the blockAttached to relevant block behaviors
Chunk Entity StorageManages active block entities and coordinates within chunk sectionscrates/pumpkin-world

The Block Registry & Dispatch System

Block interaction events are routed through the central BlockRegistry in crates/pumpkin/src/block/registry.rs:

  1. Registration: At server initialization, all behavior structs are registered into the BlockManager.
  2. Mapping: The manager maps numeric BlockId keys to thread-safe behavior instances (Arc<dyn BlockBehaviour>).
  3. Dispatch: When the network layer receives block action packets (such as CUseItemOn or 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.

Veröffentlicht unter der MIT-Lizenz.