render: extract cached M2 animation resource observer
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
| M2 build dispatch planner | Implemented extraction | [`m2-build-dispatch-planner.md`](m2-build-dispatch-planner.md) |
|
||||
| M2 build resource snapshot | Implemented extraction | [`m2-build-resource-snapshot.md`](m2-build-resource-snapshot.md) |
|
||||
| M2 static build resource observer | Implemented extraction | [`m2-static-build-resource-observer.md`](m2-static-build-resource-observer.md) |
|
||||
| M2 cached animation resource observer | Implemented extraction | [`m2-cached-animation-resource-observer.md`](m2-cached-animation-resource-observer.md) |
|
||||
| M2 build queue | Implemented extraction | [`m2-build-queue.md`](m2-build-queue.md) |
|
||||
| M2 static batch materializer | Implemented extraction | [`m2-static-batch-materializer.md`](m2-static-batch-materializer.md) |
|
||||
| M2 runtime mesh rebuild classifier | Implemented extraction | [`m2-runtime-mesh-rebuild-classifier.md`](m2-runtime-mesh-rebuild-classifier.md) |
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
|
||||
Own cross-frame bookkeeping between a successful animated M2 ResourceLoader
|
||||
request, terminal polling and budgeted main-thread scene finalization. This is
|
||||
an exact state extraction; animation eligibility and loading remain in
|
||||
`StreamingWorldLoader`, while scene finalization and retained Node lifecycle
|
||||
belong to `M2AnimatedSceneFinalizer` and `M2PrototypeCacheState`.
|
||||
an exact state extraction; cached animation eligibility and request admission
|
||||
belong to `M2CachedAnimationResourceObserver`, while scene finalization and
|
||||
retained Node lifecycle belong to `M2AnimatedSceneFinalizer` and
|
||||
`M2PrototypeCacheState`.
|
||||
|
||||
## Non-goals
|
||||
|
||||
@@ -29,8 +30,10 @@ belong to `M2AnimatedSceneFinalizer` and `M2PrototypeCacheState`.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Loader[StreamingWorldLoader] --> IO[ResourceLoader]
|
||||
Loader --> State[M2AnimationLoadPipelineState]
|
||||
Observer[M2CachedAnimationResourceObserver] --> IO[ResourceLoader request]
|
||||
Observer --> State[M2AnimationLoadPipelineState]
|
||||
Loader[StreamingWorldLoader] --> IO
|
||||
Loader --> State
|
||||
State -->|detached pending records| Loader
|
||||
Loader -->|opaque terminal status| State
|
||||
State -->|completion FIFO| Loader
|
||||
@@ -100,12 +103,13 @@ stateDiagram-v2
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant O as CachedAnimationObserver
|
||||
participant L as StreamingWorldLoader
|
||||
participant R as ResourceLoader
|
||||
participant S as M2AnimationLoadPipelineState
|
||||
participant P as M2PrototypeCacheState
|
||||
L->>R: load_threaded_request(GLB)
|
||||
L->>S: remember_request(path, GLB)
|
||||
O->>R: load_threaded_request(GLB)
|
||||
O->>S: remember_request(path, GLB)
|
||||
loop frames
|
||||
L->>S: request_records_snapshot()
|
||||
L->>R: load_threaded_get_status(GLB)
|
||||
@@ -128,8 +132,10 @@ sequenceDiagram
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Observer[M2CachedAnimationResourceObserver] --> State[M2AnimationLoadPipelineState]
|
||||
Observer --> Resource[ResourceLoader request]
|
||||
Loader[StreamingWorldLoader] --> State[M2AnimationLoadPipelineState]
|
||||
Loader --> Resource[ResourceLoader]
|
||||
Loader --> Resource
|
||||
Loader --> Budget[RenderBudgetScheduler]
|
||||
Loader --> Prototype[M2PrototypeCacheState]
|
||||
State -. no dependency .-> Resource
|
||||
@@ -142,7 +148,7 @@ flowchart TB
|
||||
| Failure | Detection | Behavior | Diagnostic | Recovery |
|
||||
|---|---|---|---|---|
|
||||
| Empty/duplicate request | State guard | Reject unchanged | Contract verifier | Correct caller or request later |
|
||||
| Request start/cache miss | Loader | No insertion; mark static | Existing loader path | Cache correction/reload |
|
||||
| Request start/cache miss | Cached observer | No insertion; mark static | Observer contract | Cache correction/reload |
|
||||
| Non-terminal status | Loader | Keep pending | Existing metric | Poll next frame |
|
||||
| Failed terminal load | Popped status | Loader marks static | Existing behavior | Future map/session reload |
|
||||
| Empty defensive path | Loader poll | Discard and mark static | Source contract | Correct producer |
|
||||
@@ -154,7 +160,7 @@ flowchart TB
|
||||
|---|---|---|---|---|
|
||||
| `enable_m2_animated_instances` | `true` | Existing renderer profile | Yes | Enables caller request path |
|
||||
| `m2_animation_finalize_ops_per_tick` | `1` | Quality/custom | Yes | Bounds caller FIFO drain |
|
||||
| Animated allow/deny/primitive rules | Existing values | Existing renderer profile | Yes | Filter before state insertion |
|
||||
| Animated allow/deny/primitive rules | Existing values | Existing renderer profile | Yes | Observer filters before state insertion |
|
||||
|
||||
## Persistence, cache and migration
|
||||
|
||||
@@ -188,7 +194,8 @@ sibling service.
|
||||
| Capability | Status | Evidence | Gap/next step |
|
||||
|---|---|---|---|
|
||||
| Animated request/finalize state | Implemented extraction | Synthetic contract/source/timing verifier | Asset-backed traversal/leak/p95/p99 pending |
|
||||
| ResourceLoader and GLB selection | Existing loader-owned | Adjacent renderer tests | I/O adapter extraction optional |
|
||||
| Cached request admission and GLB selection | Implemented in observer | Policy/GLB/source verifier | Asset-backed traversal pending |
|
||||
| Terminal ResourceLoader polling | Existing loader-owned | Shutdown/finalizer regressions | I/O adapter extraction optional |
|
||||
| Animated prototype outcomes | Implemented extraction | Prototype cache verifier | Asset-backed animation fidelity pending |
|
||||
|
||||
## Known gaps and risks
|
||||
@@ -202,9 +209,10 @@ sibling service.
|
||||
| Path | Responsibility |
|
||||
|---|---|
|
||||
| `src/render/m2/m2_animation_load_pipeline_state.gd` | Pending records, completion FIFO and metrics |
|
||||
| `src/render/m2/m2_cached_animation_resource_observer.gd` | Eligibility, GLB selection and request admission |
|
||||
| `src/render/m2/m2_animated_scene_finalizer.gd` | Candidate instantiation, material repair and player validation |
|
||||
| `src/render/m2/m2_prototype_cache_state.gd` | Animated prototype/static-only outcomes |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Eligibility, I/O, permits, instantiation and adoption |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Native eligibility/build, polling, permits and adoption |
|
||||
| `src/tools/verify_m2_animation_load_pipeline_state.gd` | Lifecycle/boundary/timing regression |
|
||||
|
||||
## Related decisions and references
|
||||
|
||||
@@ -104,7 +104,8 @@ sequenceDiagram
|
||||
- The planner owns only call-local scalar values and the returned Dictionary.
|
||||
- `M2BuildQueue` owns typed jobs, FIFO ordering, serial numbers and group/offset
|
||||
cursors. `M2BuildDispatchPlanner` owns the pure resource-state action decision;
|
||||
the loader owns tile checks, resource observation/retry and adoption calls.
|
||||
the loader owns tile checks and native-first orchestration, while static and
|
||||
cached animation observers own their observation/retry phases.
|
||||
- Materializers own main-thread Node/MultiMesh construction under loader roots.
|
||||
- The scheduler owns the frame-local `M2_BUILD` counter.
|
||||
- Pure planning is thread-safe, though the current adapter calls it on main thread.
|
||||
@@ -150,8 +151,8 @@ queue depth, build activity and hitch observability.
|
||||
|
||||
## Extension points
|
||||
|
||||
- A later package may extract resource observation/request orchestration while
|
||||
retaining the dispatch and typed build-job/FIFO contracts.
|
||||
- Remaining native resource observation may be extracted while retaining the
|
||||
dispatch and typed build-job/FIFO contracts.
|
||||
- Spatial-cell batching must use measured culling/performance evidence and must
|
||||
not silently change this model-path batch cursor.
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
|
||||
## Purpose
|
||||
|
||||
Select one M2 build action after the loader observes animation/static resource
|
||||
state. The planner makes wait priority, materializer selection and the historical
|
||||
missing-model serial transition explicit without owning resources or engine work.
|
||||
Select one M2 build action after renderer observers produce animation/static
|
||||
resource state. The planner makes wait priority, materializer selection and the
|
||||
historical missing-model serial transition explicit without owning resources or
|
||||
engine work.
|
||||
|
||||
## Non-goals
|
||||
|
||||
@@ -146,7 +147,8 @@ flowchart TB
|
||||
- Planner owns call-local comparisons and the returned Dictionary only.
|
||||
- `M2BuildResourceSnapshot` owns the typed call-local observation contract;
|
||||
dispatch reads availability/pending/missing accessors but no engine references.
|
||||
- Loader owns resource lookup/request order, action execution and permit use.
|
||||
- Loader owns native-first observation order, action execution and permit use;
|
||||
static/cached-animation observers own their lookup/request phases.
|
||||
- `M2BuildQueue` owns pending jobs, FIFO keys and progress cursors.
|
||||
- Materializers own main-thread scene construction under loader-owned roots.
|
||||
- Pure calls are thread-safe; the current loader adapter calls on main thread.
|
||||
@@ -190,16 +192,17 @@ remain unchanged.
|
||||
|
||||
## Extension points
|
||||
|
||||
A later package may move resource observation/request execution behind a service
|
||||
that produces `M2BuildResourceSnapshot`. Generic callbacks, signals and a shared
|
||||
state-machine framework remain intentionally excluded.
|
||||
Static and cached animated observation/request execution now live behind sibling
|
||||
services that produce `M2BuildResourceSnapshot`. Native animation remains an
|
||||
orchestrator-owned phase. Generic callbacks, signals and a shared state-machine
|
||||
framework remain intentionally excluded.
|
||||
|
||||
## Capability status
|
||||
|
||||
| Capability | Status | Evidence | Gap/next step |
|
||||
|---|---|---|---|
|
||||
| M2 build action selection | Implemented extraction | Priority/matrix/source/timing verifier | Asset-backed traversal pending |
|
||||
| Resource observation and requests | Loader-owned | Cache/pipeline regressions | Typed orchestration extraction pending |
|
||||
| Static/cached animation observation and requests | Implemented separately | Observer/cache/pipeline regressions | Native observation remains loader-owned |
|
||||
| Queue/cursor state | Implemented separately | M2 build queue verifier | Asset-backed traversal pending |
|
||||
| Materialization | Implemented separately | Static/animated materializer verifiers | GPU/p95/p99 evidence pending |
|
||||
|
||||
@@ -215,7 +218,8 @@ state-machine framework remain intentionally excluded.
|
||||
|---|---|
|
||||
| `src/render/m2/m2_build_dispatch_planner.gd` | Pure action priority and transition plan |
|
||||
| `src/render/m2/m2_build_resource_snapshot.gd` | Typed per-step resource observation contract |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Resource observation, action execution, permits and engine lifetime |
|
||||
| `src/render/m2/m2_cached_animation_resource_observer.gd` | Cached animation observation/request phase |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Native observation order, action execution, permits and engine lifetime |
|
||||
| `src/render/m2/m2_build_batch_planner.gd` | Batch count and cursor plan |
|
||||
| `src/render/m2/m2_build_queue.gd` | Pending jobs, FIFO and cursor ownership |
|
||||
| `src/tools/verify_m2_build_dispatch_planner.gd` | Matrix, boundary and timing regression |
|
||||
|
||||
@@ -28,7 +28,9 @@ static Mesh and terminal missing-model state. The snapshot never owns engine lif
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Loader[StreamingWorldLoader observations] --> Snapshot[M2BuildResourceSnapshot]
|
||||
Native[StreamingWorldLoader native observation] --> Snapshot[M2BuildResourceSnapshot]
|
||||
Cached[M2CachedAnimationResourceObserver] --> Snapshot
|
||||
Static[M2StaticBuildResourceObserver] --> Snapshot
|
||||
Snapshot --> Dispatch[M2BuildDispatchPlanner]
|
||||
Snapshot --> Loader
|
||||
Loader --> Animated[M2AnimatedInstanceMaterializer]
|
||||
@@ -60,8 +62,8 @@ are forbidden.
|
||||
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|
||||
|---|---|---|---|---|---|
|
||||
| Input | Normalized relative path | Loader path adapter | Snapshot/diagnostics | Copied String | Snapshot lifetime |
|
||||
| Input | Optional animated prototype | Prototype/native animation path | Snapshot/materializer adapter | Borrowed exact Node3D reference | One build operation |
|
||||
| Input | Animation request pending | Animation pipeline state | Snapshot/dispatch planner | Boolean copy | One build operation |
|
||||
| Input | Optional animated prototype | Native/cached animation observer | Snapshot/materializer adapter | Borrowed exact Node3D reference | One build operation |
|
||||
| Input | Animation request pending | Cached animation observer | Snapshot/dispatch planner | Boolean copy | One build operation |
|
||||
| Input | Optional prepared static Mesh | Mesh cache/request path | Snapshot/materializer adapter | Borrowed exact Mesh reference | One build operation |
|
||||
| Input | Static model terminally missing | Prototype cache state | Snapshot/dispatch planner | Boolean copy | One build operation |
|
||||
| Output | Availability/pending/missing values | Snapshot | Dispatch planner | Scalar reads | One dispatch plan |
|
||||
@@ -110,8 +112,12 @@ sequenceDiagram
|
||||
participant B as M2BuildBatchPlanner
|
||||
participant D as M2BuildDispatchPlanner
|
||||
participant M as M2 materializer
|
||||
L->>L: resolve/request animated prototype
|
||||
L->>S: construct(path, prototype, pending)
|
||||
L->>L: resolve native animated prototype
|
||||
L->>S: construct native result
|
||||
opt no native prototype
|
||||
L->>L: delegate cached animation observer
|
||||
L->>S: receive cached/pending snapshot
|
||||
end
|
||||
alt animation not pending
|
||||
L->>B: plan batch using snapshot availability
|
||||
opt positive static batch
|
||||
@@ -143,7 +149,8 @@ flowchart TB
|
||||
## Ownership, threading and resources
|
||||
|
||||
- Snapshot owns only copied scalar state and temporary references.
|
||||
- Prototype/cache services retain resource state; loader owns observation order.
|
||||
- Prototype/cache services retain resource state; loader owns native-first
|
||||
observation order while cached/static observers own their phases.
|
||||
- Scene roots remain loader/tile-owned; Mesh lifetime follows cache/resource refs.
|
||||
- Dispatch planner reads only snapshot accessors and never mutates the snapshot.
|
||||
- Current construction/adoption occurs on renderer main thread.
|
||||
@@ -187,9 +194,10 @@ queue/hitch metrics remain unchanged.
|
||||
|
||||
## Extension points
|
||||
|
||||
`M2StaticBuildResourceObserver` now produces the static phase. A later animated
|
||||
observer may produce the first phase. The value contract remains independent of
|
||||
both producers and of generic callback frameworks.
|
||||
`M2CachedAnimationResourceObserver` produces the cached animated phase and
|
||||
`M2StaticBuildResourceObserver` produces the static phase. Native animation
|
||||
observation remains loader-owned. The value contract stays independent of all
|
||||
producers and of generic callback frameworks.
|
||||
|
||||
## Capability status
|
||||
|
||||
@@ -198,14 +206,15 @@ both producers and of generic callback frameworks.
|
||||
| Typed per-step M2 resource observation | Implemented extraction | Identity/adoption/lifetime/source/timing verifier | Asset-backed traversal pending |
|
||||
| Dispatch decision | Implemented separately | Dispatch planner verifier | Asset-backed traversal pending |
|
||||
| Static lookup/request execution | Implemented separately | Static observer verifier | Asset-backed traversal pending |
|
||||
| Animated lookup/request execution | Loader-owned | Animation regressions | Service extraction pending |
|
||||
| Cached animated lookup/request execution | Implemented separately | Cached observer verifier | Asset-backed traversal pending |
|
||||
| Native animated lookup/build execution | Loader-owned | Native renderer regression | Service extraction pending |
|
||||
| Engine lifetime/materialization | Loader/materializer-owned | Lifetime/materializer regressions | GPU/p95/p99 evidence pending |
|
||||
|
||||
## Known gaps and risks
|
||||
|
||||
- Static observation is mutable during its short two-phase construction.
|
||||
- Raw Node3D/Mesh references remain necessary for current materializer APIs.
|
||||
- Loader still owns synchronous/native prototype attempts and ResourceLoader requests.
|
||||
- Loader still owns synchronous native prototype attempts and terminal polling.
|
||||
- Synthetic timing does not measure resource, Node or GPU work.
|
||||
|
||||
## Source map
|
||||
@@ -215,7 +224,8 @@ both producers and of generic callback frameworks.
|
||||
| `src/render/m2/m2_build_resource_snapshot.gd` | Typed per-step resource observations and diagnostics |
|
||||
| `src/render/m2/m2_build_dispatch_planner.gd` | Snapshot-to-action planning |
|
||||
| `src/render/m2/m2_static_build_resource_observer.gd` | Static snapshot production and requests |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Animated observation/request execution and materializer borrowing |
|
||||
| `src/render/m2/m2_cached_animation_resource_observer.gd` | Cached animated snapshot production and requests |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Native animation observation and materializer borrowing |
|
||||
| `src/tools/verify_m2_build_resource_snapshot.gd` | Identity/adoption/lifetime/boundary/timing regression |
|
||||
|
||||
## Related decisions and references
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
# M2 Cached Animation Resource Observer
|
||||
|
||||
## Metadata
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Status | Implemented extraction |
|
||||
| Target/work package | M03 / `M03-RND-M2-CACHED-ANIMATION-RESOURCE-OBSERVER-001` |
|
||||
| Owners | Cached animated M2 eligibility, request admission and initial snapshot |
|
||||
| Last verified | Worktree `work/sindo-main-codex/m03-m2-cached-animation-resource-observer`, 2026-07-18 |
|
||||
| Profiles/capabilities | Existing optional cached-GLB animated M2 path |
|
||||
|
||||
## Purpose
|
||||
|
||||
Produce the cached-animation phase of `M2BuildResourceSnapshot`: reuse an exact
|
||||
animated prototype, wait for a pending request, admit the first safe GLB request,
|
||||
or record a terminal static-only animation outcome without changing behavior.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Load/build native GryphonRoost animation or emit its diagnostics.
|
||||
- Poll/finalize threaded Resources or instantiate/fix imported scenes.
|
||||
- Own/free prototype Nodes, snapshots, pipeline entries or cache state.
|
||||
- Materialize instances, consume permits or change animation policy defaults.
|
||||
- Change GLB layout, cache format, batching, profiles or visible output.
|
||||
|
||||
## Context and boundaries
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Loader[StreamingWorldLoader] --> Native[Native animation attempt]
|
||||
Native -->|no prototype| Observer[M2CachedAnimationResourceObserver]
|
||||
Prototype[M2PrototypeCacheState] --> Observer
|
||||
Pipeline[M2AnimationLoadPipelineState] --> Observer
|
||||
Resource[ResourceLoader and GLB JSON] --> Observer
|
||||
Observer --> Snapshot[M2BuildResourceSnapshot]
|
||||
Snapshot --> Dispatch[M2BuildDispatchPlanner]
|
||||
```
|
||||
|
||||
## Public API
|
||||
|
||||
| Symbol | Kind | Purpose | Failure behavior |
|
||||
|---|---|---|---|
|
||||
| `observe(path, cache_dir, max_primitives, allow, deny, prototype_state, pipeline_state, debug)` | Command/query | Produce cached prototype/pending/static-only snapshot | Invalid input returns empty non-pending snapshot |
|
||||
| `find_eligible_glb_cache_path(...)` | I/O query | Select first existing safe historical candidate | Returns empty String |
|
||||
| `is_animation_path_allowed(path, allow, deny)` | Pure query | Apply stripped case-insensitive substring policy | Empty path/allowlist rejects; deny wins |
|
||||
| `cache_resource_paths(cache_dir, path)` | Pure query | Return nested/lowercase/basename GLB candidates | Empty values yield fewer candidates |
|
||||
| `glb_cache_is_safe_for_runtime_animation(path, max, debug)` | I/O query | Validate animations, primitive limit and schema | Invalid/missing GLB rejects |
|
||||
| `read_glb_json(path)` | I/O query | Read version-2 GLB JSON chunk | Returns empty Dictionary |
|
||||
| `glb_primitive_count(gltf)` | Pure query | Count primitives across meshes | Invalid entries contribute zero |
|
||||
| `glb_animation_schema(gltf)` | Pure query | Read OpenWC schema marker | Missing marker returns empty String |
|
||||
|
||||
## Inputs and outputs
|
||||
|
||||
| Direction | Data | Producer | Consumer | Ownership/lifetime |
|
||||
|---|---|---|---|---|
|
||||
| Input | Normalized M2 path/cache directory | Loader | Observer | Copied Strings; one observation |
|
||||
| Input | Primitive cap and allow/deny patterns | Loader exports | Observer | Copied/read-only call values |
|
||||
| Input | Prototype and request states | M2 state services | Observer | Borrowed services; map/session |
|
||||
| Input | Existing GLB cache file | Offline cache pipeline | Observer | Read-only file access |
|
||||
| Output | Resource snapshot | Observer | Loader/dispatch/materializer | Caller-owned snapshot; one build step |
|
||||
| Output | Borrowed exact prototype | Prototype state | Snapshot/materializer | No ownership transfer |
|
||||
| Output | Threaded request record | Observer | Animation pipeline | Pipeline-owned copied paths |
|
||||
| Output | Static-only transition | Observer | Prototype state | State-owned copied path |
|
||||
|
||||
## Data flow
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start[Observe normalized path] --> Valid{Valid composition?}
|
||||
Valid -->|no| Empty[Empty non-pending snapshot]
|
||||
Valid -->|yes| Cached{Prototype cached?}
|
||||
Cached -->|yes| Ready[Snapshot with exact prototype]
|
||||
Cached -->|no| Static{Already static-only?}
|
||||
Static -->|yes| Empty
|
||||
Static -->|no| Pending{Request exists?}
|
||||
Pending -->|yes| Wait[Pending snapshot]
|
||||
Pending -->|no| Policy{Allow and not deny?}
|
||||
Policy -->|no| Mark[Mark static-only]
|
||||
Policy -->|yes| Candidate[Historical GLB candidates]
|
||||
Candidate --> Safe{Animations, primitive cap, schema safe?}
|
||||
Safe -->|no usable| Mark
|
||||
Safe -->|yes| Request[Threaded request]
|
||||
Request -->|OK or busy| Remember[Remember and return pending snapshot]
|
||||
Request -->|error| Mark
|
||||
Mark --> Empty
|
||||
```
|
||||
|
||||
## Lifecycle/state
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Observing
|
||||
Observing --> Cached
|
||||
Observing --> Pending
|
||||
Observing --> Requested
|
||||
Observing --> StaticOnly
|
||||
Observing --> Rejected
|
||||
Cached --> [*]
|
||||
Pending --> [*]
|
||||
Requested --> [*]
|
||||
StaticOnly --> [*]
|
||||
Rejected --> [*]
|
||||
```
|
||||
|
||||
## Main sequence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant L as StreamingWorldLoader
|
||||
participant O as CachedAnimationObserver
|
||||
participant C as PrototypeCacheState
|
||||
participant P as AnimationLoadPipelineState
|
||||
participant R as ResourceLoader
|
||||
participant S as M2BuildResourceSnapshot
|
||||
L->>L: attempt native candidate
|
||||
alt no native prototype
|
||||
L->>O: observe(path, cache/policy/state)
|
||||
O->>C: find animated / static-only
|
||||
O->>P: has request
|
||||
opt eligible cache candidate
|
||||
O->>R: exists + GLB JSON + threaded request
|
||||
O->>P: remember request
|
||||
end
|
||||
O-->>L: snapshot
|
||||
else native prototype
|
||||
L->>S: construct native snapshot
|
||||
end
|
||||
```
|
||||
|
||||
## Dependency diagram
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Observer[M2CachedAnimationResourceObserver] --> Snapshot[M2BuildResourceSnapshot]
|
||||
Observer --> Prototype[M2PrototypeCacheState]
|
||||
Observer --> Pipeline[M2AnimationLoadPipelineState]
|
||||
Observer --> ResourceLoader
|
||||
Observer --> FileAccess[GLB header and JSON]
|
||||
Observer -. no dependency .-> Native[M2 native builder/repository]
|
||||
Observer -. no dependency .-> Finalizer[M2AnimatedSceneFinalizer]
|
||||
Observer -. no dependency .-> Scheduler[RenderBudgetScheduler]
|
||||
Observer -. no dependency .-> SceneTree
|
||||
```
|
||||
|
||||
## Ownership, threading and resources
|
||||
|
||||
- Observer retains no service, request, snapshot, Resource or Node reference.
|
||||
- Prototype state retains accepted Nodes and static-only paths until shutdown.
|
||||
- Pipeline state retains copied request paths until terminal polling/finalize.
|
||||
- Snapshot borrows the exact cached prototype; observer never frees it.
|
||||
- Resource existence/request and synchronous GLB JSON inspection run on the
|
||||
renderer main thread, matching the previous loader behavior.
|
||||
- Loader remains owner of native animation build, terminal polling/finalize,
|
||||
permits, materialization and every SceneTree mutation.
|
||||
|
||||
## Errors, cancellation and recovery
|
||||
|
||||
| Failure/state | Behavior | Recovery |
|
||||
|---|---|---|
|
||||
| Empty path/dependency | Return empty non-pending snapshot without mutation | Correct composition |
|
||||
| Cached prototype | Return exact reference immediately | None |
|
||||
| Existing request | Return pending without duplicate admission | Retry after terminal drain |
|
||||
| Disallowed/denied path | Mark static-only | New loader session/configuration |
|
||||
| Missing/invalid/unsafe GLB | Continue candidates, then mark static-only | Repair/rebake cache and restart session |
|
||||
| Request error | Mark static-only | New loader session/cache repair |
|
||||
| Tile cancellation | Observer retains nothing | Loader queue remains authoritative |
|
||||
| Shutdown | Loader drains requests before state clear | New loader starts empty |
|
||||
|
||||
## Configuration and capabilities
|
||||
|
||||
The service consumes existing `m2_cache_dir`, `m2_animated_max_primitives`,
|
||||
`m2_animated_allowlist_patterns`, `m2_animated_denylist_patterns` and debug flag.
|
||||
It adds no setting and preserves runtime mutability and defaults.
|
||||
|
||||
## Persistence, cache and migration
|
||||
|
||||
No persistence or cache format changes are introduced. Existing `.glb` candidate
|
||||
layout and OpenWC schema markers are read unchanged; no rebake is required.
|
||||
|
||||
## Diagnostics and observability
|
||||
|
||||
Unsupported non-empty schemas preserve the historical optional
|
||||
`M2_ANIM_REJECT` debug line. Snapshot and pipeline diagnostics remain detached;
|
||||
queue and hitch metrics are unchanged.
|
||||
|
||||
## Verification
|
||||
|
||||
- Dedicated verifier covers invalid/cached identity/static/pending/missing
|
||||
lifecycle, allow/deny semantics, exact path order, generated GLB header/JSON,
|
||||
animation presence, primitive cap, accepted/rejected schemas, source boundaries
|
||||
and bounded timing.
|
||||
- Snapshot, dispatch, pipeline, prototype, shutdown, facade, internal-access and
|
||||
checkpoint regressions protect adjacent behavior.
|
||||
- Fidelity evidence is exact policy/I/O extraction. No original-client visual or
|
||||
animation parity claim is made.
|
||||
|
||||
## Extension points
|
||||
|
||||
Native animation observation can become a sibling service without changing this
|
||||
cached-GLB contract. Terminal ResourceLoader polling/finalization may later move
|
||||
behind a dedicated adapter while retaining the pipeline state.
|
||||
|
||||
## Capability status
|
||||
|
||||
| Capability | Status | Evidence | Gap/next step |
|
||||
|---|---|---|---|
|
||||
| Cached animation observation/request | Implemented extraction | Lifecycle/policy/GLB/source/timing verifier | Asset-backed traversal pending |
|
||||
| Native animation observation | Existing loader-owned | Native renderer regression | Separate extraction |
|
||||
| Animated finalize/preparation | Loader/finalizer split | Pipeline/finalizer regressions | Polling adapter optional |
|
||||
|
||||
## Known gaps and risks
|
||||
|
||||
- A successful asynchronous request is not started by the unit fixture because
|
||||
leaving it undrained leaks process work; source and pipeline tests cover admission.
|
||||
- Generated GLB metadata fixtures validate policy, not Godot import fidelity.
|
||||
- Private traversal, leak/descriptor pressure, p95/p99 and paired visuals remain
|
||||
unavailable without private assets.
|
||||
|
||||
## Source map
|
||||
|
||||
| Path | Responsibility |
|
||||
|---|---|
|
||||
| `src/render/m2/m2_cached_animation_resource_observer.gd` | Cached GLB policy, request and snapshot production |
|
||||
| `src/render/m2/m2_build_resource_snapshot.gd` | Typed per-step observation value |
|
||||
| `src/render/m2/m2_animation_load_pipeline_state.gd` | Pending request/finalize state |
|
||||
| `src/render/m2/m2_prototype_cache_state.gd` | Prototype and static-only outcomes |
|
||||
| `src/scenes/streaming/streaming_world_loader.gd` | Native attempt, composition, finalize and execution |
|
||||
| `src/tools/verify_m2_cached_animation_resource_observer.gd` | Lifecycle/policy/GLB/boundary/timing regression |
|
||||
|
||||
## Related decisions and references
|
||||
|
||||
- [`m2-build-resource-snapshot.md`](m2-build-resource-snapshot.md)
|
||||
- [`m2-animation-load-pipeline-state.md`](m2-animation-load-pipeline-state.md)
|
||||
- [`m2-prototype-cache-state.md`](m2-prototype-cache-state.md)
|
||||
- [`m2-animated-scene-finalizer.md`](m2-animated-scene-finalizer.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)
|
||||
@@ -28,7 +28,9 @@ paths and paths whose animation fallback is static-only.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Loader[StreamingWorldLoader] --> State[M2PrototypeCacheState]
|
||||
Observer[M2 resource observers] --> State
|
||||
Resource[ResourceLoader / raw builders] --> Loader
|
||||
Resource --> Observer
|
||||
State --> Static[Static prototype Node3D]
|
||||
State --> Animated[Animated prototype Node3D]
|
||||
State --> Missing[Missing-model path set]
|
||||
@@ -62,7 +64,7 @@ Mesh traversal and other application layers are forbidden.
|
||||
| Input | Normalized non-empty M2 path | Loader normalization | Cache state | Copied String key | Shutdown lifetime |
|
||||
| Input | Detached static Node3D | Cached scene/raw builder adapter | Cache state | Adopted on success | Until final shutdown |
|
||||
| Input | Detached animated Node3D | GLB/native animation adapter | Cache state | Adopted on success | Until final shutdown |
|
||||
| Input | Missing/static-only outcome | Loader failure/fallback adapter | Cache state | Boolean set entry | Until final shutdown |
|
||||
| Input | Missing/static-only outcome | Loader/observer failure adapter | Cache state | Boolean set entry | Until final shutdown |
|
||||
| Output | Canonical prototype Node3D | Cache state | Loader instance/material adapter | Borrowed exact reference | One lookup/use |
|
||||
| Output | Detached path-only snapshot | Cache state | Tests/diagnostics | Fresh caller-owned arrays | One query |
|
||||
|
||||
@@ -135,9 +137,10 @@ sequenceDiagram
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Loader[StreamingWorldLoader] --> State[M2PrototypeCacheState]
|
||||
Observer[M2 resource observers] --> State
|
||||
State --> Node3D
|
||||
Loader --> Raw[M2RawModelRepository]
|
||||
Loader --> ResourceLoader
|
||||
Observer --> ResourceLoader
|
||||
Loader --> StaticBuilder[M2Builder]
|
||||
Loader --> AnimatedBuilder[M2NativeAnimatedBuilder]
|
||||
State -. no dependency .-> Raw
|
||||
@@ -165,7 +168,7 @@ flowchart TB
|
||||
| Unknown positive lookup | Map miss | Return null | Path snapshot | Loader continues existing load/fallback |
|
||||
| Duplicate candidate | Occupied valid path | Release candidate; return first | Identity fixture | None required |
|
||||
| Model source/load failure | Loader result | Mark missing outcome | Existing fallback behavior | New loader session/source repair |
|
||||
| Animation unavailable/unsafe | Loader policy/result | Mark static-only outcome | Existing fallback behavior | New loader session/cache repair |
|
||||
| Animation unavailable/unsafe | Observer/native result | Mark static-only outcome | Existing fallback behavior | New loader session/cache repair |
|
||||
| Shutdown | Loader lifecycle | Release positive and clear all state | Shutdown verifier | New loader begins empty |
|
||||
| Cancellation | Not owned | No state transition inside this service | N/A | Loader drains/cancels before shutdown clear |
|
||||
|
||||
@@ -177,8 +180,8 @@ flowchart TB
|
||||
| Negative cache lifetime | Final loader shutdown | All | No | Preserves historical fallback suppression |
|
||||
| Eviction capacity | Unbounded historical behavior | All | No | No mid-session Node destruction |
|
||||
|
||||
Animation enablement, candidate/allow/deny rules, cache paths and per-frame
|
||||
permits remain loader configuration.
|
||||
Animation enablement, candidate/allow/deny rules and cache paths remain loader
|
||||
configuration consumed by the cached observer. Per-frame permits remain loader-owned.
|
||||
|
||||
## Persistence, cache and migration
|
||||
|
||||
@@ -188,7 +191,8 @@ and native M2 formats are unchanged; no migration or rebake is introduced.
|
||||
## Diagnostics and observability
|
||||
|
||||
- `diagnostic_snapshot` exposes four sorted path arrays without Node references.
|
||||
- Existing `M2_ANIM_CACHE` and native animation logs remain loader-owned.
|
||||
- Cached eligibility rejection logging belongs to the cached observer; native
|
||||
animation logs remain loader-owned.
|
||||
- Existing renderer queue metrics remain unchanged because these tables never
|
||||
contributed work counts.
|
||||
- Normalized relative path remains the correlation key.
|
||||
@@ -208,8 +212,8 @@ and native M2 formats are unchanged; no migration or rebake is introduced.
|
||||
## Extension points
|
||||
|
||||
Eviction or byte/count budgets require measured memory evidence and explicit
|
||||
prototype-user lifetime rules. Animation request-state extraction can consume
|
||||
this service without moving ResourceLoader or builder ownership into it.
|
||||
prototype-user lifetime rules. Cached animation observation consumes this
|
||||
service without moving ResourceLoader or builder ownership into prototype state.
|
||||
|
||||
## Capability status
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ from externally reading/writing loader-private queue, task, cache and tile-state
|
||||
| `M2BuildDispatchPlanner.plan_step` | Internal pure M2 service | Selects wait, animated/static materialization or no-Node advancement from observed resource state | Main/any thread; stateless | Pending animation has priority; unresolved static Mesh waits |
|
||||
| `M2BuildResourceSnapshot` | Internal M2 value contract | Carries per-step normalized path, animated/static references and pending/missing observations | Renderer main thread; one build operation | Values retained exactly; release never frees resources |
|
||||
| `M2StaticBuildResourceObserver.observe` | Internal M2 I/O service | Produces cached/pending/requested/missing static snapshot phase | Renderer main thread; stateless | Invalid composition rejected; no candidate marks missing |
|
||||
| `M2CachedAnimationResourceObserver.observe` | Internal M2 I/O service | Produces cached/pending/static-only animated snapshot phase | Renderer main thread; stateless | Invalid composition returns empty snapshot; no safe candidate marks static-only |
|
||||
| `M2BuildQueue` / `M2BuildJob` | Internal M2 pending-state service | Own typed root/groups/cursor jobs and FIFO/stale tile keys | Renderer main thread; map session | Invalid enqueue rejected; stale keys drain independently of jobs |
|
||||
| `M2StaticBatchMaterializer.materialize_batch` | Internal M2 scene-materialization service | Builds and attaches one prepared-Mesh MultiMesh transform slice | Renderer main thread; stateless after each call | Invalid/empty input returns null; bounds are caller precondition |
|
||||
| `M2RuntimeMeshRebuildClassifier` | Internal memoized M2 service | Detects billboard/UV-rotation metadata requiring stale cached-mesh rebuild | Renderer main thread; cached until reset | Invalid variants/indices skipped; first path decision wins |
|
||||
@@ -193,7 +194,7 @@ loader configuration remains transitional composition data, not a caller API.
|
||||
| Internal grouping | Tile origin, M2 names and placements | Loader / `M2PlacementGrouper` | Loader worker result/build job | Fresh Dictionary/Transform3D arrays | One grouping task |
|
||||
| Internal batch plan | Transform count/offset, path kind and limits | Loader / `M2BuildBatchPlanner` | Loader materialization/cursor adapter | Fresh scalar Dictionary | One build operation |
|
||||
| Internal M2 dispatch plan | Batch count and observed animation/static resource state | Loader / `M2BuildDispatchPlanner` | Loader queue/materializer/progress adapter | Fresh scalar/action Dictionary | One build operation |
|
||||
| Internal M2 resource observation | Normalized path, optional prototype/Mesh and pending/missing flags | Loader / `M2BuildResourceSnapshot` | Dispatch planner and loader materializer adapter | Snapshot borrows exact engine references | One build operation |
|
||||
| Internal M2 resource observation | Normalized path, optional prototype/Mesh and pending/missing flags | Loader / M2 observers / `M2BuildResourceSnapshot` | Dispatch planner and loader materializer adapter | Snapshot borrows exact engine references | One build operation |
|
||||
| Internal M2 pending build | Tile key, M2 root, grouped transforms and cursors | Loader / `M2BuildQueue` | Loader readiness, planner and materializer adapters | Queue-owned job/keys and strong references | Until finish/cancel/clear/replacement |
|
||||
| Internal static M2 materialization | Parent, prepared Mesh, ordered transform slice and render settings | Loader / `M2StaticBatchMaterializer` | Attached MultiMeshInstance3D | Parent owns node/MultiMesh; exact Mesh reference retained | One main-thread build batch |
|
||||
| Internal WMO placement | Path, MODF placement, tile/index | Loader / `WmoPlacementResolver` | WMO caches, registry and three instance adapters | Value-only String/Transform3D | Lookup/placement lifetime |
|
||||
@@ -204,7 +205,7 @@ loader configuration remains transitional composition data, not a caller API.
|
||||
| Internal WMO scene cache | Normalized path, `.tscn` path and validated PackedScene | Loader / `WmoSceneResourceCacheState` | Loader lookup, request poll and scene instantiation | State-owned PackedScene/path references; detached request snapshots | Until transient/full clear |
|
||||
| Internal ADT water load | Tile key, ADT path, task ID and parsed Dictionary | Loader/worker / `AdtWaterLoadPipelineState` | Loader task start, budgeted drain and finalization | State-owned records; mutex result mailbox | Request through result completion/reset |
|
||||
| Internal raw M2 read | Extracted directory and normalized relative path | Loader / `M2RawModelRepository` | Finalizer, static or animated builder adapters | Fresh Dictionary; repository retains nothing | One synchronous native call |
|
||||
| Internal animated M2 load | Normalized path, cached GLB path and opaque terminal status | Loader / `M2AnimationLoadPipelineState` | Loader poll/finalize adapters | State-owned String/status records; detached pending snapshots | Request through terminal finalize/reset |
|
||||
| Internal animated M2 load | Normalized path, cached GLB path and opaque terminal status | Cached observer / loader / `M2AnimationLoadPipelineState` | Loader poll/finalize adapters | State-owned String/status records; detached pending snapshots | Request through terminal finalize/reset |
|
||||
| Internal animated M2 candidate | Loaded PackedScene, static material root and detached candidate | Loader / `M2AnimatedSceneFinalizer` | Loader prototype adoption/static fallback | Finalizer owns until rejection or exact-root transfer | One main-thread finalize permit |
|
||||
| Internal animated M2 playback | Prototype/instance native animators, path/index and player inventory | Materializer/finalizer / `M2AnimationPlaybackController` | Native and imported animation state | Borrowed Nodes; detached optional diagnostics | One duplicated instance startup |
|
||||
| Internal animated M2 materialization | Parent, prototype, ordered transform slice and render settings | Loader / `M2AnimatedInstanceMaterializer` | Attached animated batch and indexed diagnostics | Parent owns batch; caller owns detached diagnostics | One main-thread build batch |
|
||||
@@ -395,9 +396,11 @@ sequenceDiagram
|
||||
`M2BuildQueue` owns typed pending jobs, FIFO/stale keys, grouped-transform
|
||||
references and group/offset/serial cursors without freeing engine objects.
|
||||
`M2StaticBuildResourceObserver` owns static Mesh lookup/request admission and
|
||||
snapshot adoption. `M2StaticBatchMaterializer` owns static MultiMesh
|
||||
construction/attachment; the loader retains animated observation/requests,
|
||||
action execution, cursor adoption, root cleanup, budgets and Editor ownership.
|
||||
snapshot adoption. `M2CachedAnimationResourceObserver` owns cached animated
|
||||
prototype lookup, GLB policy/request admission and snapshot production.
|
||||
`M2StaticBatchMaterializer` owns static MultiMesh construction/attachment; the
|
||||
loader retains native animation observation, action execution, cursor adoption,
|
||||
root cleanup, budgets and Editor ownership.
|
||||
- `WmoPlacementResolver` is stateless and owns only call-local cache-key,
|
||||
identity and transform values. `WmoPlacementRegistry` owns only placement-key
|
||||
reference sets. `WmoRenderBuildStepPlanner` owns only a call-local operation
|
||||
@@ -422,6 +425,11 @@ sequenceDiagram
|
||||
cache path selection, request admission and initial snapshot adoption. The
|
||||
loader retains ResourceLoader polling/finalize, permits and terminal adoption;
|
||||
prototype cache state owns shared missing outcomes.
|
||||
- `M2AnimationLoadPipelineState` owns animated M2 pending Resource paths, opaque
|
||||
terminal statuses and completion-order finalize FIFO. The cached animation
|
||||
observer owns allow/deny/path/GLB selection, request admission and initial
|
||||
snapshot production. The loader retains native animation build, ResourceLoader
|
||||
polling/finalize, permits and terminal adoption.
|
||||
- `M2MeshResourceCacheState` owns prepared static Mesh references and releases
|
||||
them at the existing final-shutdown site. Prototype state and materialization
|
||||
belong to the sibling cache service and loader respectively.
|
||||
@@ -584,6 +592,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
|
||||
| M2 build dispatch planner | Implemented extraction | Scene-free priority/action/transition/source/timing contract | Resource observation/orchestration and asset-backed traversal remain pending |
|
||||
| M2 build resource snapshot | Implemented extraction | Typed identity/adoption/lifetime/source/timing contract | Resource observation service and asset-backed traversal remain pending |
|
||||
| M2 static build resource observer | Implemented extraction | Cache/pending/path/request/source/timing contract | Asset-backed traversal and finalize extraction pending |
|
||||
| M2 cached animation resource observer | Implemented extraction | Cache/pending/policy/GLB/request/source/timing contract | Native observation and asset-backed traversal pending |
|
||||
| M2 build queue | Implemented extraction | Typed lifecycle/FIFO/progress/lifetime/source/timing contract | Resource dispatch and asset-backed traversal remain pending |
|
||||
| M2 animation load pipeline state | Implemented extraction | Synthetic lifecycle/FIFO/source/timing contract | Asset-backed traversal/leak/animation-fidelity/p95/p99 pending |
|
||||
| M2 animated scene finalizer | Implemented extraction | Synthetic type/lifetime/material/player/source/timing contract | Asset-backed GLB traversal/material/animation comparison pending |
|
||||
@@ -658,6 +667,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
|
||||
| `src/render/m2/m2_build_dispatch_planner.gd` | M2 wait/materializer/advance action priority and transition plan |
|
||||
| `src/render/m2/m2_build_resource_snapshot.gd` | Typed per-step animated/static observations and borrowed references |
|
||||
| `src/render/m2/m2_static_build_resource_observer.gd` | Static Mesh lookup/request/missing snapshot production |
|
||||
| `src/render/m2/m2_cached_animation_resource_observer.gd` | Cached animated GLB policy/request/snapshot production |
|
||||
| `src/render/m2/m2_build_job.gd` | M2 root/groups references and group/offset/serial progress |
|
||||
| `src/render/m2/m2_build_queue.gd` | Keyed pending jobs and FIFO/stale tile-key lifecycle |
|
||||
| `src/render/m2/m2_mesh_load_pipeline_state.gd` | Static M2 pending Resource paths, terminal statuses and finalize FIFO |
|
||||
@@ -689,6 +699,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
|
||||
| `src/tools/verify_m2_build_dispatch_planner.gd` | M2 dispatch priority/action/transition/boundary/timing regression |
|
||||
| `src/tools/verify_m2_build_resource_snapshot.gd` | M2 observation identity/adoption/lifetime/boundary/timing regression |
|
||||
| `src/tools/verify_m2_static_build_resource_observer.gd` | Static lookup/request/path/boundary/timing regression |
|
||||
| `src/tools/verify_m2_cached_animation_resource_observer.gd` | Cached animation lifecycle/policy/GLB/boundary/timing regression |
|
||||
| `src/tools/verify_m2_build_queue.gd` | M2 job/FIFO/progress/lifetime/boundary/timing regression |
|
||||
| `src/tools/verify_m2_mesh_load_pipeline_state.gd` | Static M2 request/terminal/FIFO/boundary/timing regression |
|
||||
| `src/tools/verify_m2_mesh_resource_cache_state.gd` | Static M2 Mesh cache ownership/lifetime/boundary/timing regression |
|
||||
|
||||
Reference in New Issue
Block a user