Home Visibility, Maps & Coordinates

Visibility, Exploration Maps, Coordinates & Inventory


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 sim module 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 Spawn snapshot (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 |


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 t for forward compatibility but servers reject t != 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 the terminal client
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)

10. ADR candidates


Parent doc: 00-initial-vision.html — update cross-references when ADRs land.