105 lines
6.1 KiB
Markdown
105 lines
6.1 KiB
Markdown
# 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`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/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`](/developer/codegen).
|
|
2. **Dynamic Behavior Layer ([`pumpkin::block`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin/src/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:
|
|
|
|
| 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`:
|
|
|
|
```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`](/developer/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**:
|
|
|
|
| Component | Responsibility | Implementation File |
|
|
| :--- | :--- | :--- |
|
|
| `BlockEntity` Trait | Defines NBT serialization (`to_nbt`, `from_nbt`) and tick execution | [`crates/pumpkin/src/block/entities/`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/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`](https://github.com/Pumpkin-MC/Pumpkin/tree/master/crates/pumpkin-world) |
|
|
|
|
---
|
|
|
|
## The Block Registry & Dispatch System
|
|
|
|
Block interaction events are routed through the central `BlockRegistry` in [`crates/pumpkin/src/block/registry.rs`](https://github.com/Pumpkin-MC/Pumpkin/blob/master/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](/developer/blocks/adding-blocks)**: Complete walk-through of declaring attributes, implementing interaction hooks, creating block entities, and registering behaviors.
|