f4d5e29cc9
Work-Package: M03-RND-WMO-RENDER-GROUP-MATERIALIZER-001 Agent: sindo-main-codex Tests: 63/64 autonomous verifiers passed; proprietary ADT probe unavailable; baseline dry-run 7/7; documentation and coordination gates passed Fidelity: exact behavior-preserving node materialization extraction; no new 3.3.5a parity claim
215 lines
9.9 KiB
Markdown
215 lines
9.9 KiB
Markdown
# WMO Render Group Materializer
|
|
|
|
## Metadata
|
|
|
|
| Field | Value |
|
|
|---|---|
|
|
| Status | Implemented |
|
|
| Target | M03 Renderer Facade and Safe Extraction |
|
|
| Work package | `M03-RND-WMO-RENDER-GROUP-MATERIALIZER-001` |
|
|
| Owner | Render |
|
|
| Last verified | 2026-08-01 |
|
|
|
|
## Purpose
|
|
|
|
`WmoRenderGroupMaterializer` creates and attaches one lightweight cached WMO
|
|
render group on the renderer main thread. It owns the duplicated
|
|
`MeshInstance3D`/`MultiMeshInstance3D` presentation rules that previously lived
|
|
inside `StreamingWorldLoader`.
|
|
|
|
## Non-goals
|
|
|
|
- select a build step, advance/cancel a job or consume a render permit;
|
|
- load, cache, validate or finalize WMO Resources;
|
|
- resolve placement transforms or own the placement root;
|
|
- choose Editor persistence policy or serialize generated nodes;
|
|
- change WMO cache formats, materials, visibility or shadow policy.
|
|
|
|
## Context and boundaries
|
|
|
|
The loader obtains a queue-owned WMO root and render Resource, asks
|
|
`WmoRenderBuildStepPlanner` for one operation, and finalizes the selected Mesh.
|
|
The materializer then performs only indexed node presentation and attachment.
|
|
The loader retains scheduler, queue and Editor composition responsibilities.
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
Queue[WmoRenderBuildQueue] --> Loader[StreamingWorldLoader]
|
|
Planner[WmoRenderBuildStepPlanner] --> Loader
|
|
Loader --> Finalizer[WmoRuntimeMeshFinalizer]
|
|
Loader --> Materializer[WmoRenderGroupMaterializer]
|
|
Materializer --> MeshNode[MeshInstance3D]
|
|
Materializer --> MultiMeshNode[MultiMeshInstance3D]
|
|
MeshNode --> Root[Queue-owned WMO Node3D root]
|
|
MultiMeshNode --> Root
|
|
Loader --> EditorOwner[Optional Editor owner assignment]
|
|
```
|
|
|
|
## Public API
|
|
|
|
| Symbol | Role | Thread/lifetime | Failure behavior |
|
|
|---|---|---|---|
|
|
| `materialize_mesh_group(...)` | Create, configure and attach one indexed Mesh group | Renderer main thread; stateless after return | Null/invalid parent, null Mesh or negative index returns null |
|
|
| `materialize_multimesh_group(...)` | Create, configure and attach one indexed MultiMesh doodad group | Renderer main thread; stateless after return | Null/invalid parent, null MultiMesh or negative index returns null |
|
|
|
|
Both methods preserve exact Resource identity. `group_index` selects the optional
|
|
name and transform; missing names use the historical indexed fallback and a
|
|
missing transform leaves `Transform3D.IDENTITY`. Positive visibility range
|
|
applies its caller-supplied margin. Shadow mode is always applied explicitly.
|
|
|
|
## Inputs and outputs
|
|
|
|
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|
|
|---|---|---|---|---|---|
|
|
| Input | Queue-owned WMO `Node3D` root | `WmoRenderBuildQueue` via loader | Materializer | Borrowed; not retained | One main-thread call |
|
|
| Input | Selected `Mesh` or `MultiMesh` | WMO render Resource via loader | Materializer | Borrowed exact Resource | Parent-node lifetime after attach |
|
|
| Input | Names, transforms and selected index | WMO render Resource/planner via loader | Materializer | Borrowed value collections | One call |
|
|
| Input | Visibility end/margin and shadow flag | Loader quality profile | Materializer | Scalar values | One call |
|
|
| Output | Attached `MeshInstance3D` or `MultiMeshInstance3D` | Materializer | Loader/SceneTree | Parent root owns node and Resource reference | Until placement release/world teardown |
|
|
|
|
Side effects:
|
|
|
|
- allocates exactly one Godot geometry node for valid input;
|
|
- applies name, optional transform, shadow and optional visibility settings;
|
|
- attaches the node exactly once to the supplied WMO root.
|
|
|
|
It performs no filesystem, ResourceLoader, worker, RenderingServer RID, cache,
|
|
queue, permit, logging or direct Editor-owner mutation.
|
|
|
|
## Data flow
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
Input[Root + Resource + indexed metadata + render settings] --> Validate{Valid root/resource/index?}
|
|
Validate -->|no| Null[Return null; no attachment]
|
|
Validate -->|yes| Kind{Mesh or MultiMesh method}
|
|
Kind --> Mesh[Create MeshInstance3D]
|
|
Kind --> Multi[Create MultiMeshInstance3D]
|
|
Mesh --> Configure[Name + optional transform + render settings]
|
|
Multi --> Configure
|
|
Configure --> Attach[Attach once to WMO root]
|
|
Attach --> Return[Return borrowed attached node]
|
|
```
|
|
|
|
## Main sequence
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Loader as StreamingWorldLoader
|
|
participant Queue as WmoRenderBuildQueue
|
|
participant Finalizer as WmoRuntimeMeshFinalizer
|
|
participant Materializer as WmoRenderGroupMaterializer
|
|
participant Root as WMO Node3D root
|
|
Loader->>Queue: read front job and cursors
|
|
Loader->>Finalizer: finalize selected Mesh
|
|
Loader->>Materializer: materialize selected group
|
|
Materializer->>Root: add_child(geometry instance)
|
|
Materializer-->>Loader: attached node or null
|
|
Loader->>Loader: optional Editor ownership
|
|
Loader->>Queue: adopt planned cursors
|
|
Loader->>Loader: consume one group permit
|
|
```
|
|
|
|
## Dependency diagram
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
Loader[StreamingWorldLoader] --> Materializer[WmoRenderGroupMaterializer]
|
|
Materializer --> Engine[Node3D / GeometryInstance3D / Mesh / MultiMesh]
|
|
Materializer -. no dependency .-> IO[ResourceLoader / FileAccess]
|
|
Materializer -. no dependency .-> Queue[WmoRenderBuildQueue]
|
|
Materializer -. no dependency .-> Scheduler[RenderBudgetScheduler]
|
|
Materializer -. no dependency .-> Finalizer[WmoRuntimeMeshFinalizer]
|
|
```
|
|
|
|
## Ownership, threading and resources
|
|
|
|
- Both public methods are main-thread only because they mutate the SceneTree.
|
|
- The caller owns the parent root; after attachment the root owns the new node.
|
|
- The node retains the exact input Mesh or MultiMesh Resource reference.
|
|
- The service retains no Node, Resource, RID, collection or per-group state.
|
|
- Loader-owned optional recursive Editor ownership runs after successful return.
|
|
|
|
## Errors, cancellation and recovery
|
|
|
|
| Failure/state | Detection | Behavior | Recovery |
|
|
|---|---|---|---|
|
|
| Null/freed parent | Guard | Return null; allocate/attach nothing | Caller validates current queue job |
|
|
| Null Resource | Guard | Return null | Loader advances the historically selected cursor |
|
|
| Negative index | Guard | Return null | Planner supplies non-negative selected indices |
|
|
| Missing name | Bounds check | Use `Group_N` or `DoodadGroup_N` | Rebuild cache metadata if desired |
|
|
| Missing transform | Bounds check | Retain identity transform | Rebuild cache metadata if desired |
|
|
| Placement cancellation | Loader/queue | Parent and children released by existing lifecycle | Re-request placement later |
|
|
| Shutdown | Loader lifecycle | Service has no retained state to drain | New loader composes a new service |
|
|
|
|
## Configuration, capabilities and profiles
|
|
|
|
The service introduces no configuration or capability. It accepts the existing
|
|
`wmo_visibility_range`, `CHUNK_SIZE` margin and `wmo_cast_shadows` values chosen
|
|
by the loader quality profile. Blizzlike and Enhanced selection remains outside.
|
|
|
|
## Persistence, cache and migrations
|
|
|
|
No persisted data or cache format changes. The service neither reads nor writes
|
|
WMO cache files and requires no migration or rebake.
|
|
|
|
## Diagnostics and observability
|
|
|
|
The service emits no logs or metrics. Existing `wmo_groups` queue depth, build
|
|
permits and loader lifecycle diagnostics remain authoritative.
|
|
|
|
## Verification and fidelity evidence
|
|
|
|
- `verify_wmo_render_group_materializer.gd` covers exact Mesh/MultiMesh identity,
|
|
indexed and fallback names, optional transforms, shadows, positive/disabled
|
|
visibility, attachment, invalid input, source boundaries and 1,000 groups.
|
|
- Adjacent WMO queue/planner/finalizer and checkpoint regressions protect the
|
|
unchanged orchestration and visible output.
|
|
- This is an exact code-motion extraction of existing Godot presentation rules;
|
|
it adds no original-client 3.3.5a visual parity claim.
|
|
|
|
## Performance budgets
|
|
|
|
The synthetic contract requires 1,000 simple Mesh group materializations in
|
|
under one second. Production work remains limited to one group per scheduler
|
|
permit. Asset-backed CPU/GPU p95/p99 and long traversal remain required evidence.
|
|
|
|
## Extension points
|
|
|
|
- Asset-backed WMO traversal can measure group attachment and lifetime without
|
|
changing this API.
|
|
- Additional render settings belong here only when they apply equally to both
|
|
lightweight group-node kinds and have fidelity evidence.
|
|
|
|
## Capability status
|
|
|
|
| Capability | Status | Evidence | Gap/next step |
|
|
|---|---|---|---|
|
|
| Mesh group materialization | Implemented extraction | Identity/name/transform/render/attachment contract | Asset-backed visual/GPU p95/p99 pending |
|
|
| MultiMesh doodad group materialization | Implemented extraction | Identity/name/transform/render/attachment contract | Asset-backed traversal/leak evidence pending |
|
|
| Build planning/queue progress | Loader-owned | Existing planner/queue regressions | Further orchestration extraction pending |
|
|
| Editor persistence ownership | Loader-owned | Source-boundary contract | Editor scene-save integration evidence pending |
|
|
|
|
## Known gaps and risks
|
|
|
|
- SceneTree node creation remains synchronous main-thread work by design.
|
|
- The synthetic fixture does not measure private WMO assets, GPU upload, portal
|
|
visibility, original-client visuals, long traversal or leak behavior.
|
|
|
|
## Source map
|
|
|
|
| Path | Responsibility |
|
|
|---|---|
|
|
| `src/render/wmo/wmo_render_group_materializer.gd` | Indexed geometry-node creation, settings and attachment |
|
|
| `src/scenes/streaming/streaming_world_loader.gd` | Composition, finalization, queue, permits, Editor ownership and lifecycle |
|
|
| `src/tools/verify_wmo_render_group_materializer.gd` | Synthetic contract, ownership boundary and timing regression |
|
|
|
|
## Related decisions and references
|
|
|
|
- [`wmo-render-build-step-planner.md`](wmo-render-build-step-planner.md)
|
|
- [`wmo-render-build-queue.md`](wmo-render-build-queue.md)
|
|
- [`wmo-runtime-mesh-finalizer.md`](wmo-runtime-mesh-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)
|