Files
open-wc/docs/modules/terrain-chunk-geometry-queue-planner.md

8.9 KiB

Terrain Chunk Geometry Queue Planner

Metadata

Field Value
Status Implemented extraction
Target/work package M03 / M03-RND-TERRAIN-CHUNK-QUEUE-001
Owners Pure chunk geometry create/remove request calculation
Last verified Worktree work/sindo-main-codex/m03-terrain-chunk-queue, 2026-07-16
Profiles/capabilities Existing chunk/tile LOD desired state; all profiles

Purpose

Compare loader-owned current chunk geometry with desired chunk/tile LOD state and produce fresh removal and nearest-first creation request arrays.

Non-goals

  • Retain, drain or bound queues, or own per-frame operation permits.
  • Create/remove Mesh, Node, material or RID resources.
  • Calculate desired chunk/tile LOD, parse ADT data or schedule worker tasks.
  • Change cache versions, renderer profiles or visible fidelity rules.
  • Provide a generic queue/operation framework.

Context and boundaries

flowchart LR
    Current[Loader-owned tile/chunk state] --> Planner[TerrainChunkGeometryQueuePlanner]
    Desired[Desired chunk and tile LOD state] --> Planner
    Focus[GodotWorldPosition] --> Planner
    Planner --> Remove[Stable-order remove requests]
    Planner --> Create[Nearest-first create requests]
    Remove --> Loader[StreamingWorldLoader queues]
    Create --> Loader
    Loader --> Budget[RenderBudgetScheduler permit]
    Budget --> GPU[Existing Mesh/Node/RID side effects]

Allowed dependencies are typed Godot position and call-local scalar/container values. SceneTree, RenderingServer, ResourceLoader, worker APIs, gameplay, network, editor UI, files and persistent caches are forbidden.

Public API

Symbol Kind Purpose Thread/lifetime Errors
TerrainChunkGeometryQueuePlanner.plan(tile_states, focus_position) Pure query Return fresh create_requests and remove_requests arrays Synchronous; caller owns result Null/wrong focus returns two empty arrays

Script-identity validation uses a preload and therefore works from a cold Godot global-class cache.

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input Tile-state read model with current chunks and desired LODs Streamer Planner Loader-owned; read only One rebuild
Input Desired tile LOD Tile LOD calculation Planner Scalar in loader state One rebuild
Input Parsed chunk origins and tile fallback origin ADT result/loader Planner Loader-owned; read only Map session
Input GodotWorldPosition Streamer focus adapter Planner Immutable caller reference One rebuild
Output Remove {tile, chunk} records Planner Loader removal queue Fresh caller array/dictionaries Until drained/rebuilt
Output Create {tile, chunk, lod, dist_sq} records Planner Loader creation queue Fresh nearest-first array/dictionaries Until drained/rebuilt

Distance is horizontal XZ squared distance from the chunk origin, not its center. Y is intentionally ignored. A missing/sparse parsed origin falls back to the tile state's existing origin exactly as before extraction.

Data flow

flowchart TD
    Start[plan] --> FocusValid{Typed focus?}
    FocusValid -->|no| Empty[Return two empty arrays]
    FocusValid -->|yes| Tile[Iterate tile state insertion order]
    Tile --> TileLod{Desired tile LOD active?}
    TileLod -->|yes| RemoveAll[Append every current chunk removal]
    TileLod -->|no| Compare[Compare current and desired chunks]
    Compare --> RemoveMissing[Append current chunks absent from desired]
    Compare --> CreateMismatch[Append LOD-mismatched creates]
    Compare --> CreateMissing[Append absent desired creates]
    CreateMismatch --> Origin[Parsed chunk origin or tile fallback]
    CreateMissing --> Origin
    Origin --> Distance[Attach squared XZ distance]
    RemoveAll --> Next[Next tile]
    RemoveMissing --> Next
    Distance --> Next
    Next --> Sort[Sort creates nearest-first]
    Sort --> Result[Return fresh arrays]

Lifecycle/state

The planner is stateless. Each loader queue rebuild supplies current read models and receives new arrays. The loader adopts and drains those arrays until another rebuild replaces them. Planner destruction requires no cleanup or cancellation.

Main sequence

sequenceDiagram
    participant Loader as StreamingWorldLoader
    participant Planner as TerrainChunkGeometryQueuePlanner
    participant Budget as RenderBudgetScheduler
    participant Render as Existing terrain finalization
    Loader->>Planner: plan(tile states, typed focus)
    Planner-->>Loader: fresh create/remove arrays
    Loader->>Budget: request shared chunk_geometry permit
    Budget-->>Loader: permit
    Loader->>Render: pop_back removal first
    Loader->>Budget: request shared chunk_geometry permit
    Budget-->>Loader: permit
    Loader->>Render: pop_front nearest creation

Ownership, threading and resources

  • The planner owns only call-local arrays and dictionaries until return.
  • The loader owns adopted queue storage, drain ordering, tile/chunk state and all Mesh/Node/material/RID side effects.
  • Calls and drains currently run on the renderer main thread. The planner has no lock, task, retained resource or concurrent mutation.
  • Removal and creation continue to share the existing chunk_geometry budget lane.

Errors, cancellation and recovery

Failure Detection Behavior Diagnostic Recovery
Null/wrong focus script Identity guard Return empty request arrays Contract verifier Supply typed focus and rebuild
Sparse/out-of-range chunk data Origin resolver Use tile fallback origin Synthetic fixture Normal ADT completion restores precise origin
Tile LOD becomes desired Desired tile LOD check Remove every current chunk; no chunk creates Queue metrics Existing tile-LOD create path takes over
Queue rebuild before drain Loader lifecycle Replace old desired-operation arrays Existing queue metrics Latest state wins
Shutdown/map reset Loader lifecycle Loader clears queues; planner has nothing to cancel Shutdown verifier New session replans

Configuration and capabilities

The planner introduces no settings. It consumes already-calculated desired LOD state. Operation limits, profile defaults and removal-first drain order remain loader/scheduler configuration.

Persistence, cache and migration

No serialization, cache entry or format changes. Baked terrain, control-splat and splat caches require no rebuild or migration.

Diagnostics and observability

The planner emits no logs. Existing queue metrics observe the adopted arrays. The contract verifier reports semantic cases and bounded multi-tile timing. Asset-backed p95/p99 remains milestone acceptance work.

Verification

  • verify_terrain_chunk_geometry_queue_planner.gd: missing/mismatched/unchanged chunks, tile-LOD removal, sparse origin fallback, XZ-only distance, stable removals, nearest creates, invalid focus, loader boundary and bounded timing.
  • Existing LOD planner, terrain cache, facade, internal-access, manifest, shutdown, scheduler, streaming and coordinate regressions remain required.
  • Fidelity evidence is exact branch/request/order preservation only. No new build-12340 visual parity claim is made.

Extension points

  • Extract tile-LOD operation planning as its own bounded contract if justified.
  • Add explicit typed tile-state adapters only when more than one consumer exists.

Capability status

Capability Status Evidence Gap/next step
Pure chunk create/remove planning Implemented extraction Asset-free semantic/source/timing verifier Asset-backed p95/p99 pending
Queue execution/resource ownership Remains in loader Drain source boundary and scheduler regression Further terrain decomposition required

Known gaps and risks

  • Raw tile/chunk dictionaries remain a transitional ADT adapter boundary.
  • The planner performs a second linear tile-state pass beside tile-LOD planning; bounded synthetic timing is green, but asset-backed frame metrics are pending.
  • Equal-distance create ordering retains comparator behavior without a tie-breaker.
  • Terrain geometry finalization and state mutation remain monolithic.

Source map

Path Responsibility
src/render/terrain/terrain_chunk_geometry_queue_planner.gd Pure request calculation and nearest-first creation order
src/scenes/streaming/streaming_world_loader.gd Queue adoption, tile-LOD planning, budgets and render side effects
src/tools/verify_terrain_chunk_geometry_queue_planner.gd Semantic, boundary and timing regression