Files
open-wc/docs/modules/wmo-scene-resource-cache-state.md
T

10 KiB

WMO Scene Resource Cache State

Metadata

Field Value
Status Implemented
Target/work package M03 / M03-RND-WMO-SCENE-RESOURCE-CACHE-001
Owners Validated cached-WMO PackedScenes, negative cache and pending request paths
Last verified Worktree work/sindo-main-codex/m03-wmo-scene-resource-cache, 2026-07-17
Profiles/capabilities Cached WMO .tscn fallback; profile-independent state

Purpose

Own mutually exclusive cached, missing and pending states for normalized WMO scene paths. The state accepts only caller-validated PackedScene references and records .tscn paths for threaded requests whose I/O, size limit and cache metadata validation remain in StreamingWorldLoader.

Non-goals

  • Normalize WMO paths, build .tscn paths or measure files.
  • Call ResourceLoader/FileAccess, instantiate scenes or validate cache metadata.
  • Own live prototypes, placement/build jobs, instantiated Nodes or RIDs.
  • Change missing, oversize, request-error, retry or fallback behavior.
  • Persist, migrate or build WMO caches.

Context and boundaries

flowchart LR
    Lookup[Normalized WMO scene lookup] --> Loader[StreamingWorldLoader]
    Loader --> State[WmoSceneResourceCacheState]
    Loader --> Size[File existence and size limit]
    Size --> ResourceLoader[Godot ResourceLoader]
    ResourceLoader --> Loader
    Loader --> Probe[Instantiate, metadata/version check, free]
    Probe -->|accepted PackedScene or missing| State
    Loader --> Live[Live-prototype fallback]

The module retains validated PackedScenes and copied paths only. ResourceLoader, FileAccess, WMOBuilder, Node, RID, worker, gameplay, network and editor concerns remain outside it.

Public API

Symbol Kind Purpose Thread/lifetime Errors
scene_for(path) / contains_scene(path) Query Borrow/test validated PackedScene Renderer main thread; until full clear Empty/unknown returns null/false
is_missing(path) / has_request(path) Query Test negative/pending state Renderer main thread Empty returns false
remember_request(path, cache_path) Command/query Record loader-started request Until terminal/reset Invalid/occupied returns false
mark_missing(path) Command/query Record absent/oversize/request-start failure without pending state Until transient/full clear Invalid/occupied returns false
request_paths_snapshot() Query Copy pending normalized/cache-path mapping Poll/shutdown drain Detached Dictionary
complete_request_with_scene(path, scene) Command/query Remove pending and adopt validated PackedScene Terminal poll Unknown/null returns false
complete_request_as_missing(path) Command/query Remove pending and adopt negative state Terminal poll Unknown returns false
clear_transient_state() Command Clear pending/missing and retain scenes Map reset/request drain Idempotent
clear_all() Command Release scenes and transient state Final runtime-cache release Idempotent
pending_request_count() Query Preserve renderer queue metric Diagnostics None
diagnostic_snapshot() Query Return sorted detached scalar keys Tests/diagnostics No PackedScene exposure

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input Normalized WMO path Placement resolver through loader State Copied String Cache lifetime
Input .tscn path after accepted request start Loader Pending state Copied String Until terminal/reset
Input Metadata/version-validated PackedScene Loader probe adapter Scene cache Strong reference Until full clear
Input Missing decision Loader file/size/request/load/validation adapters Negative cache Boolean membership Until transient/full clear
Output Borrowed PackedScene State Loader scene instantiation State retains reference Lookup/instantiate call
Output Detached request snapshot State Loader polling/shutdown Caller-owned Dictionary One drain pass

Data flow

flowchart TD
    Lookup --> Known{Cached, missing or pending?}
    Known -->|cached| Return[Return PackedScene]
    Known -->|missing/pending| Null[Return null]
    Known -->|absent| Check[Loader checks file and size]
    Check -->|missing/oversize| Mark[mark_missing]
    Check -->|allowed| Request[Start threaded request]
    Request -->|error| Mark
    Request -->|accepted| Remember[remember_request]
    Remember --> Poll[Loader polls snapshot]
    Poll -->|failure| CompleteMissing[complete as missing]
    Poll -->|loaded| Validate[Instantiate and validate cache metadata]
    Validate -->|valid| CompleteScene[complete with scene]
    Validate -->|invalid| CompleteMissing

Lifecycle/state

Each normalized path is Absent, Pending, Cached or Missing. Direct file, size and request-start rejection moves Absent directly to Missing; terminal loads move Pending to Cached or Missing. Transient clear retains Cached, while full clear returns every path to Absent.

stateDiagram-v2
    [*] --> Absent
    Absent --> Pending: accepted request
    Absent --> Missing: absent, oversize or request error
    Pending --> Cached: validated PackedScene
    Pending --> Missing: load or validation failure
    Pending --> Absent: transient/full clear
    Missing --> Absent: transient/full clear
    Cached --> Absent: full clear

Main sequence

sequenceDiagram
    participant Loader as StreamingWorldLoader
    participant State as WmoSceneResourceCacheState
    participant RL as ResourceLoader
    Loader->>State: cached/missing/pending queries
    Loader->>Loader: exists and wmo_max_runtime_scene_mb check
    Loader->>RL: load_threaded_request(.tscn)
    Loader->>State: remember_request(normalized, path)
    loop renderer tick
        Loader->>State: request_paths_snapshot()
        Loader->>RL: load_threaded_get_status(path)
    end
    Loader->>RL: load_threaded_get(path)
    Loader->>Loader: instantiate, validate WMO metadata, free probe
    Loader->>State: complete with scene or as missing

Ownership, threading and resources

  • State owns three Dictionaries and strong references to accepted PackedScenes.
  • Loader owns paths, file measurement, requests, validation and all Node lifetime.
  • All mutation is serialized on the renderer main thread; no mutex is required.
  • Detached request snapshots allow terminal removal while polling.
  • Scene instantiation borrows the PackedScene and does not transfer cache ownership.

Errors, cancellation and recovery

Failure/state Detection Behavior Recovery
Missing .tscn Loader ResourceLoader existence check Direct missing state Transient reset permits later retry
Oversize .tscn Loader byte limit Missing plus unchanged debug log Raise limit/rebuild, then reset
Request-start/load failure Loader error/status Direct or terminal missing Reset and retry later
Wrong type/stale metadata Loader PackedScene/probe validation Terminal missing; probe freed Rebuild cache and reset
Shutdown while pending Loader drains snapshot Clear transient, then full cache release New loader starts absent

Configuration and capabilities

No setting is added. wmo_cache_dir, wmo_max_runtime_scene_mb, request timing, quality profiles and WMO build budgets stay loader-owned.

Persistence, cache and migration

The module is runtime-only. Existing WMOBuilder cache metadata/version checks remain unchanged and execute before state adoption. No cache format, migration or rebuild is introduced.

Diagnostics and observability

Pending count preserves the existing wmobuild metric contribution. The snapshot exposes sorted scene/missing/request keys only. Existing oversize logging remains in the loader; the state emits no logs.

Verification

  • verify_wmo_scene_resource_cache_state.gd: invalid input, direct missing, exclusivity, request completion, partial/full reset, diagnostics, boundaries and bounded timing.
  • verify_render_runtime_cache_shutdown.gd: loader full release of scenes, negative and pending state.
  • Adjacent WMO/renderer regressions verify unchanged lookup/fallback behavior. This extraction makes no visual or build-12340 parity claim.

Extension points

  • A later I/O adapter may consume request snapshots while retaining this contract.
  • Scene instantiation/material preparation can be extracted separately because it owns Nodes and main-thread side effects rather than cache state.

Capability status

Capability Status Evidence Gap/next step
Cached WMO PackedScene state Implemented extraction Lifecycle/source/timing and shutdown verifiers Asset-backed traversal/leak evidence pending
Size and cache metadata validation Preserved in loader Source boundary and WMO regressions Oversize/stale asset fixtures could follow
ResourceLoader I/O and live fallback Partial/loader-owned Existing runtime behavior Separate extraction if justified

Known gaps and risks

  • PackedScenes remain strongly referenced until final shutdown cache release.
  • Negative caching suppresses retries until transient reset, matching prior behavior.
  • No proprietary WMO corpus, stale/oversize asset fixture, leak run, traversal p95/p99 or paired original-client capture is included.

Source map

Path Responsibility
src/render/wmo/wmo_scene_resource_cache_state.gd Scene/missing/request state and resets
src/scenes/streaming/streaming_world_loader.gd Paths, file limit, requests, validation, fallback and Node lifetime
src/tools/verify_wmo_scene_resource_cache_state.gd State, boundary and timing regression
src/tools/verify_render_runtime_cache_shutdown.gd Loader final cache ownership regression