213 lines
10 KiB
Markdown
213 lines
10 KiB
Markdown
# 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
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```mermaid
|
|
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`.
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```mermaid
|
|
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 |
|
|
|
|
## Related decisions and references
|
|
|
|
- [`wmo-render-resource-cache-state.md`](wmo-render-resource-cache-state.md)
|
|
- [`wmo-render-build-queue.md`](wmo-render-build-queue.md)
|
|
- [`world-renderer.md`](world-renderer.md)
|
|
- [`../../RENDER.md`](../../RENDER.md)
|
|
- [`../../targets/roadmap/02-rendering-and-graphics.md`](../../targets/roadmap/02-rendering-and-graphics.md)
|