6. Blockstate Model
6.1 Derive by default, promote on override
Section titled “6.1 Derive by default, promote on override”By default the compiler derives blockstate from position and neighbours: stair facing, door orientation, glass-pane and fence and wall connections, chest left/right, and so on.
Any blockstate that can be architectural intent is overridable, and the moment you write it, it is promoted to intent. Cairn does not adopt the strong reading, “if it can be derived, don’t let the author write it”. The rule is “derive by default; any blockstate that can be intent is overridable”.
Cases that MUST stay overridable, because each can be intent:
| Group | States |
|---|---|
| Stairs | facing (a stair as a chair or decoration), half=top (upside-down eaves), shape |
| Furniture | chest size=single (auto-merging from adjacency is forbidden), bed facing, door hinge / open |
| Orientation | log / pillar axis (a horizontal beam), trapdoor open / half, glazed_terracotta rotation |
| Counts | snow layers, candle count |
| Redstone | redstone_dust connect, repeater delay, observer / piston / dispenser facing, note / instrument |
Two easy-to-miss cases belong to derivation, not intent: torch ↔ wall_torch and sign ↔
wall_sign are substituted automatically by attachment face.
stair id=eave kind=stairs mat_slot=roof side=front half=top facing=out shape=outer_left # eavesbeam id=lintel kind=pillar mat_slot=frame at=front.top axis=x # horizontal beamchest id=store at=inside.back size=singlenote_block at=2,1,2 instrument=bit note=126.2 intent_state and resolved_state
Section titled “6.2 intent_state and resolved_state”member: id: eave type: block | block_entity | entity # typed in the IR; the distinction is the compiler's job primitive: stairs intent_state: { half: top, shape: outer_left } # author intent. Edit diffs look only here resolved_state: { facing: north, waterlogged: false } # derived, including paint-derived stateThe two are named apart from Minecraft’s own term “blockstate” on purpose. Keeping resolved state (derived or paint-origin) out of intent state (authored) is what makes edits stable.
bed is treated as a block member rather than an entity, to keep the IR types clean.
6.3 waterlogged
Section titled “6.3 waterlogged”The default is paint-derived: when fill fluid=water overlaps a waterloggable block, the compiler
sets waterlogged.
A three-valued waterlogged=auto|true|false is allowed, for leaving an air pocket inside a tank
(explicit false), distinguishing source from flowing, and version differences in the waterloggable
table. Flowing water is made explicit with flow= and level=.
fill fluid=water kind=source from=1,1,1 to=5,3,5 # overlapping fences/stairs/signs auto-waterloggedtrapdoor id=shutter at=.. waterlogged=false # an air window in a tankwater id=stream from=.. flow=east level=4