Visibility, Exploration Maps, Coordinates & Inventory
1. Summary
Three related systems define what a player perceives and what the server sends them:
| System | Question it answers | Primary driver |
|---|---|---|
| Network horizon (AOI) | Which live entities get tick updates to this client? | Performance |
| Exploration knowledge | Which terrain and static features does this player know? | Gameplay / progression |
| Cartography (skill + ledger) | Permanent character knowledge; map items are inputs and trade goods | Progression / economy / social |
These must stay conceptually separate but compose when building each client's view. Sending every player and NPC in the entire Area to every client is not viable at 30–60 Hz — a horizon (area of interest) is required. The cartography ledger (§4) is the permanent fog-of-war mask; live entities still require AOI.
World position is modeled as (x, y, z, w) with t reserved at 0 until a future design pass (§6).
2. Network Horizon (Area of Interest)
2.1 Recommendation: Yes — mandatory from Phase 1
There is no need to transmit full updates for distant entities. Every successful MMO uses interest management (AOI). Without it:
- Bandwidth scales O(players × entities) instead of O(players × nearby entities)
- Encode cost on the server becomes the bottleneck before sim does
- 100 players × 500 NPCs @ 60 Hz is untenable; 100 × ~15 nearby is fine
Rule: A client receives high-frequency tick deltas only for entities inside their network horizon. Everything else is omitted (not even “stale” updates).
2.2 Layered rings — omnidirectional
The character looks all around — no forward-facing cone for AOI or exploration. Interest zones are cylindrical or spherical around the observer's position (x,y,z):
top-down (all directions equal)
beyond
╭─────────────────╮
│ horizon │
│ ╭─────────╮ │
│ │ core │ │
│ │ ● │ │ ← player; radius, not facing
│ ╰─────────╯ │
╰─────────────────╯
| Ring | Radius (tunable) | Update rate | Contents |
|---|---|---|---|
| Core | scale-aware (§2.3) | Every sim tick (30–60 Hz) | Positions, combat state, animations, projectiles |
| Horizon | 2× core (typical) | 5–10 Hz or on change | Position + identity only; no fine combat detail |
| Beyond | outside horizon | None | No entity stream; optional ambient events (see §2.5) |
Radii are per-Area config and may scale with observer body size class. Cartography skill does not extend combat AOI — only map revelation efficiency (§4).
Implemented (2026-07-11): entity AOI uses horizontal radius AOI_CORE_RADIUS_M (32 m) and vertical half-extent AOI_Z_EXTENT_M (6 m) — entities on adjacent z-bands (platforms, cliffs) are visible; distant floors are filtered. See crates/sim/src/aoi.rs query_radius_z.
2.3 Multi-scale spatial grid (decided)
A single fixed chunk size cannot represent a child-sized human, a giant monster, and a city building equally well. Use a hierarchical grid with a small micro-cell base and larger macro-cells for big footprints and terrain LOD.
Scale classes
| Class | Example entities | Footprint (indicative) |
|---|---|---|
| Tiny | Child, small creature, familiar | ≤ 1 m |
| Small | Human adolescent | 1–2 m |
| Medium | Adult human, wolf | 2–4 m |
| Large | Horse, ogre | 4–12 m |
| Huge | Giant, dragon, house | 12–64 m |
| Structure | Building, wall segment, terrain tile | 64 m+ |
Grid levels
| Level | Cell size (default) | Used for |
|---|---|---|
| L0 micro | 1 m | Tiny/Small/Medium entity AOI, fine exploration reveal |
| L1 meso | 8 m | Large entities, interior rooms, combat clustering |
| L2 macro | 64 m | Huge entities, buildings, terrain blocks, map LOD |
Rules:
- Every entity registers in all levels its axis-aligned bounding volume touches
- AOI subscription: player at L0 cell + rings in all directions; also subscribe L1/L2 cells overlapping horizon radius
- Giants span many L1/L2 cells — one entity, many grid keys; fan-out uses entity keys, not point sampling
- Buildings / terrain are static at L2 (and L1 for doorways); streamed when cartography or AOI includes that cell
- Per-Area manifest can tune cell sizes (dungeon: smaller L2; overworld: larger L2)
World position (47.3, 12.8, z=2) → L0 (47,12) L1 (5,1) L2 (0,0) // example floor
Giant bbox 48m × 40m → occupies L2 cells in 1×1 or more
Child bbox 0.8m → single L0 cell
Why this satisfies the scale requirement
- Small characters resolve to 1 m cells — movement and reveal are precise, not swallowed by 32 m buckets
- Giants don't force the whole world onto 1 m grids — they register at L1/L2 without per-tick full-map scans
- Buildings and terrain live at macro levels; micro exploration still records "I walked past this wall" at L0 for cartography
Implementation sketch:
CellKey { area: w, level: L0|L1|L2, cx, cy, cz }
EntityId → set<CellKey> // from bbox at each level
PlayerId → subscribed cells = omnidirectional horizon ∩ union of levels
Per tick: dirty entities fan-out to players subscribed to any overlapping cell
2.4 Spatial indexing (summary)
- Omnidirectional radius + hierarchical cells — not a forward cone
- Cell crossing triggers subscribe/unsubscribe — amortizes work across ticks
- Cartography revelation uses primarily L0 (and promotes aggregates to L1/L2 for map display); AOI uses all relevant levels
2.5 What about “I know the map but nothing is near me?”
Exploration knowledge (§3–4) does not imply live entity streams. A player with a full cartography ledger for an Area still only receives AOI-filtered entity updates. Their map view shows ledger terrain; live dots for players/NPCs appear only in core/horizon.
Optional ambient channel (low bandwidth): non-positional hints beyond horizon — e.g. “distant explosion”, weather front, faction alert. Gossip, not per-entity state.
2.6 Join, leave, teleport
- Entity enters horizon: reliable
Spawnsnapshot (full component subset), then tick deltas - Entity leaves horizon:
Despawn(client keeps exploration data; removes live entity) - Teleport (w changes): only when changing realm (OSS); within one world, use movement/portals (
01)
2.7 Protocol impact
- Per-client interest set maintained server-side (authoritative)
- Tick packets are per-client filtered — same sim, different views
- Metrics:
interest_set_size,bytes_per_client_tick,subscription_churn
2.8 Design feedback
| Idea | Verdict |
|---|---|
| Horizon for performance | Strong yes — non-negotiable for targets in 00-initial-vision.html §5 |
| Send all entities “just in case” | No — wastes bandwidth; clients cannot use the data |
| Same radius for map fog and network | No — decouple; fog is knowledge, horizon is presence |
| Horizon only (no exploration) | Possible for Phase 1 spike; add fog in Phase 2 |
| Omnidirectional AOI | Yes — no facing requirement; radius-based | | Single global chunk size | No — use L0/L1/L2 hierarchy (§2.3) | | Horizon only (no cartography) | Possible for Phase 1 spike; ledger in Phase 2 |
3. Omnidirectional exploration reveal
When a character moves or stands, they perceive all around them — same as AOI philosophy.
3.1 Revelation sweep
Each revelation pass (on cell entry or periodic while idle):
- Center on
(x,y,z); sweep 360° horizontally and configured z bands (current floor ± adjacent layers) - Mark L0 micro-cells within reveal radius
R_reveal R_revealdefaults from body size class; Cartography skill increases radius and/or cells-per-tick efficiency (§4.3)- Optional later: line-of-sight raycast to trim cells behind solid L2 walls — not required for Phase 1
3.2 What gets revealed
| Data | Stored in ledger |
|---|---|
| Terrain type / walkability | L0, aggregated to L2 for map UI |
| Static props & resource nodes | L0 cell markers |
| Building footprints | L2 when any exterior L0 touched |
| Labels (town names, POI) | on first L0 of POI or from map item annotations |
4. Cartography — skill, ledger & map items
Cartography is a first-class character skill and a permanent knowledge store, not just consumable scrolls.
4.1 Two layers: ledger vs items
| Layer | Persistence | Role |
|---|---|---|
| Cartography ledger | Permanent per character, central-persisted | Source of truth for "what I know" about each Area w |
| Map items | Physical inventory objects | Loot, trade goods, quest rewards; input to ledger |
Effective map view = cartography ledger for Area w (always). Map items in bags are optional until added to cartography.
4.2 Adding a map to cartography (decided)
When a player buys, finds, loots, or receives a map item, they get a prompt (TUI / CLI: flatland cartography add <item>):
- Add to cartography — permanent merge into ledger; item may be consumed or kept (item template flag)
- Keep in inventory only — tradeable; ledger unchanged until they add later
Merge is server-authoritative (§4.6). Once added, knowledge persists across sessions (death impact TBD in 07-death-and-respawn.html).
4.3 Cartography skill
Trainable skill affecting exploration efficiency and crafted map quality:
| Skill effect | Low skill | High skill |
|---|---|---|
Reveal radius R_reveal |
base | +up to 50% |
| Cells revealed per movement tick | 1× | 2–3× (efficient path mapping) |
| Crafted map region size | small bounds | large bounds |
| Map detail / annotation slots | coarse | fine labels, danger marks |
| Craft time & material cost | higher | lower |
| Sale value / NPC recognition | low | high |
Skill XP from: walking unrevealed L0 cells, completing surveys, crafting maps, first-time Area discovery.
4.4 Map item sources (decided)
Maps enter the economy through:
- Player craft — from own ledger subset (Cartography skill gate)
- Player trade / sale — physical item then add-to-cartography
- NPC vendors — regional maps, partial Areas
- Quest rewards — scripted regions
- Monster drops — rare survey loot
- World placement — chests, hidden caches (Area-authored)
All map items are central-signed payloads (§4.5). Forgery impossible without server.
4.5 Map item payload (server-signed)
MapItemData {
cartographer_id, // player id or "world" for authored drops
area_id (w),
created_at_tick,
bounds: ChunkRegion, // L0/L1/L2 region
chunk_bits: CompressedBitmap,
annotations: Vec<Label>,
skill_tier, // quality at creation
consume_on_add: bool, // destroy when added to ledger?
signature: CentralSig,
}
- Physical item — inventory space (§5); droppable, tradable
- Add to cartography — permanent ledger merge; item consumed if
consume_on_add
4.6 Ledger merge rules
CartographyLedger {
character_id,
areas: Map<AreaId, AreaCartography>,
}
AreaCartography {
l0_bits: SparseBitmap, // primary
l2_summary: SparseBitmap, // derived for UI zoom-out
annotations: Vec<Label>,
version,
}
When adding map M or revealing by walking:
for cell in M.cells:
ledger[cell] = merge(ledger[cell], M[cell])
- Prefer higher
reveal_strength/skill_tier - Annotations: union; conflicts show both or higher-tier wins
- Walking always upgrades own reveal strength for cells visited
4.7 Player-crafted maps for sale / share
- Select region ⊆ ledger for Area
w - Skill + station check → mint
MapItemDatawith quality tier - Sell on trade, give to alt, drop for others to add to cartography
- Enables knowledge economy — explorers monetize routes without sharing live AOI
4.8 Design feedback
| Idea | Verdict |
|---|---|
| Permanent cartography ledger | Yes — decided |
| Optional add-from-map-item | Yes — sharing & rewards |
| Cartography skill | Yes — efficiency + craft quality |
| Maps as drops / NPC / quest | Yes — progression hooks |
| Death clears ledger | No — ledger persists (07-death-and-respawn.html) |
5. Complex Inventory
5.1 Design intent
Inventory is a management game, not a bottomless list. Players make meaningful choices about what to carry — including maps, tools, resources, and consumables.
5.2 Dimensions of complexity (proposed)
| Mechanic | Description |
|---|---|
| Weight | Encumbrance affects movement speed, stamina regen |
| Volume / slots | Containers have grid or slot counts; items have shapes (later) |
| Container nesting | Bags inside bags — depth limit |
| Equipment layers | Armor slots, accessories, hotbar, quest items |
| Item instances | Durability, charges, unique affixes |
| Binding | BoP, BoE, BoU — affects trade |
| Sorting / tags | Player organization; agent CLI inventory list --tag map |
| Bank / stash | Central-persisted overflow (Phase 2+) |
| Loot overflow | Drop to ground or mail if full — player problem |
5.3 Map items in inventory
- Occupy scroll/map slot class; quality tiers vary size
- Atlases combine regions but weigh more
- Unadded maps are trade goods; ledger holds permanent knowledge after add
5.4 TUI / cartography commands
- Cartography panel — per-Area coverage %, ledger view, pending map items
- World panel — fog from ledger; live entities on explored cells in AOI only
- Agent CLI:
flatland cartography show --area w,flatland cartography add <item>, JSON export
5.5 Server authority
All container mutations are transactions on central or area inventory service:
- Atomic move, split stack, craft consume, equip
- Validation: capacity, weight, permissions, combat lockout
- Full audit log for high-value items
5.6 TUI requirements (inventory)
Multi-pane inventory: equipped | bags | weight bar | quick filters
Map items: preview region bounds before read
Agent mode:
flatland inv move, structured JSON graph of containersMap items: preview bounds; prompt add-to-cartography vs keep
6. World coordinates (x, y, z, w) — t deferred
6.1 Definition (decided)
| Dim | Name | Type | Meaning |
|---|---|---|---|
| x | easting | f32 or fixed | Horizontal axis within Area |
| y | northing | f32 or fixed | Horizontal axis within Area |
| z | elevation / layer | i32 or f32 | Vertical — floors, caves, sky layers |
| w | realm / deployment | RealmId — 0 = live world; separate OSS deployments use other ids |
Which Area shard |
| t | time slice | i64 |
Fixed at 0 for all gameplay until redesigned |
struct WorldCoord {
x: f32,
y: f32,
z: i32,
w: AreaId,
t: i64, // always 0 for now; field reserved in protocol
}
Use w (not a) in docs and APIs.
6.2 Semantics (current)
- Teleportation changes
w; sets arrival(x,y,z) t = 0— single live timeline; no time travel, historical maps, or temporal shards in scope- Protocol and DB columns include
tfor forward compatibility but servers rejectt != 0
6.3 Spatial indexing
Live sim indexes (w, level, cx, cy, cz) only — t not part of spatial keys.
6.4 Future t (out of scope)
When revisited, see prior notes: temporal maps, instanced flashbacks, separate sim per epoch. No implementation until explicitly replanned.
| Idea | Current verdict |
|---|---|
x,y,z,w |
Active |
t in protocol as reserved 0 |
Yes |
t gameplay |
Deferred indefinitely |
7. How the systems compose
Player at WorldCoord (x,y,z,w, t=0)
│
├─► Multi-scale grid (L0/L1/L2) + omnidirectional AOI ──► tick deltas
│
├─► Cartography ledger(w) ──► permanent fog / map UI
│
├─► Map items ──► optional add-to-cartography (permanent merge)
│
├─► Cartography skill ──► reveal efficiency & craft quality
│
└─► Inventory ──► map items as trade goods until added
Effective map view = cartography ledger for w (not ephemeral item reads).
8. Phasing
| Phase | Deliverable |
|---|---|
| 1 | L0/L1/L2 grid + omnidirectional AOI; (x,y,z,w), t=0 |
| 2 | Cartography ledger + 360° reveal on movement; fog TUI |
| 3 | Cartography skill; map items; add-to-cartography; craft for trade |
| 4 | Horizon LOD ring; NPC/drop/quest authored maps |
| 5 | Line-of-sight trim (optional); party reveal (optional) |
9. Open questions
Resolved (2026-07-06):
| # | Decision |
|---|---|
| M1 | 1 m L0 cell — global, no per-region overrides |
| M2 | ~32 m base reveal radius (human), scale by body class + cartography skill |
| M3 | Per template — consume_on_add flag on map items |
| M4 | Full 3D movement on z (flight/swim/climb per skills) |
| M5 | No LoS trim for cartography Phase 1 |
| M6 | Opt-in party cartography share (leader toggles) |
10. ADR candidates
Parent doc: 00-initial-vision.html — update cross-references when ADRs land.