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
.tscnpaths 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 |