Skip to main content

Furniture registry

Multi-block furniture

A bed spans six blocks, a door four. One is the anchor; the rest are fillers that store the offset back to it.

BlockMountAPI.mountOnBlock measures the sleeping position from the anchor, so mounting on a filler offsets the pose by exactly that filler's distance.

int filler = section.getFiller(x, y, z);
int dx = FillerBlockUtil.unpackX(filler);

The sign of the offset is undocumented, so FurnitureAnchorHelper.anchorOf tries both directions and validates the one landing on a block with the same id and filler == 0. This is the same data the game's /inspectfiller reads.

Neighbourhood heuristics were tried first and are wrong: the anchor does not reliably sit in any particular direction.

The registries

RegistryHoldsKey
BedRegistry.BEDSBedPos (position + lying-axis yaw)anchor
ChestRegistry.CHESTSHouseBlockPosanchor

Both are static and global, with no world scope — known debt.

Who populates them

PathWhen
BedPlaceBlockEventSystemOn the place event — beds, chests, crops, farmland
PlayerJoinHandlerRadius-32 scan on join, delayed 2 s for chunks to load
BedEntityRegistrySystemBeds that are entities rather than blocks
SimNPCPersistenceRestoring an NPC that already had a bed

Place events and the scan share BedWorldBootstrap.registerBedAt, so a bed placed by hand and one found by the scan produce identical records.

The historical bug

The place event did not register beds at all, and the only scan was called from inside /simtale housecheck as a side effect. Old worlds worked because someone had run the command there, and static registries kept the state alive. See Lessons learned.

Classification comes from the engine

BlockModule.getComponent(ItemContainerBlock.getComponentType(), world, x, y, z) != null

The same component NPCs read when looking for food, so registration and consumption cannot diverge.

ChestRegistry.isChestId (name-based) remains only as a fallback and is marked unreliable.

BedRegistry.isBedId is still name-based (contains "bed", excluding bedrock). Known debt.

House scope

HouseManager.canOpenChest refuses chests belonging to no house. That is what keeps NPCs out of world-generated loot chests, since the scan registers any container in range.

Accepted side effect: a player's chest in an open field is ignored until it is part of a house.