9.0 KiB
WMO Render Build Step Planner
Metadata
| Field | Value |
|---|---|
| Status | Implemented |
| Target/work package | M03 / M03-RND-WMO-RENDER-BUILD-PLANNER-001 |
| Owners | Pure mesh-first WMO render-group cursor decision |
| Last verified | Worktree work/sindo-main-codex/m03-wmo-render-build-planner, 2026-07-17 |
| Profiles/capabilities | Lightweight WMO render-cache path; profile-independent |
Purpose
Select exactly one next lightweight WMO render build operation from mesh and MultiMesh counts/cursors. The planner makes the ordering and cursor transition testable without loading a WMO, creating a Node or consuming a frame budget.
Non-goals
- Own render Resources, Nodes, materials, jobs, queues or permits.
- Read WMO arrays, create group instances or adopt cursors in a job.
- Change group ordering, names, transforms, shadows or visibility.
- Load, validate, version or persist a WMO cache.
- Implement portals, rooms, doodad semantics or WMO visual parity.
Context and boundaries
flowchart LR
Cache[WMOStreamingResource arrays] --> Loader[StreamingWorldLoader]
Job[Loader mesh/MultiMesh cursors] --> Loader
Loader --> Planner[WmoRenderBuildStepPlanner]
Planner --> Step[Operation + selected index + next cursors]
Step --> Loader
Loader --> Material[Material refresh]
Loader --> Node[MeshInstance3D or MultiMeshInstance3D]
Loader --> Budget[RenderBudgetScheduler permit]
The planner depends only on RefCounted, integers, StringName and a fresh
Dictionary result. Node, Resource, Mesh, MultiMesh, RID, SceneTree, files,
threads, locks, caches, gameplay, network and editor UI are forbidden.
Public API
| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|---|---|---|---|---|
OPERATION_MESH |
Constant | Identifies one mesh-group operation | Immutable | None |
OPERATION_MULTIMESH |
Constant | Identifies one doodad MultiMesh-group operation | Immutable | None |
OPERATION_COMPLETE |
Constant | Identifies exhausted mesh and MultiMesh ranges | Immutable | None |
plan_step(mesh_count, mesh_index, multimesh_count, multimesh_index) |
Pure query | Select one operation, selected index and next cursors | Any thread; caller-owned result | No clamp/error branch; raw integer comparisons are preserved |
Inputs and outputs
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|---|---|---|---|---|---|
| Input | Mesh array count and current mesh cursor | Loader resource/job adapter | Planner | Integer values | One call |
| Input | MultiMesh array count and current MultiMesh cursor | Loader resource/job adapter | Planner | Integer values | One call |
| Output | mesh, multimesh or complete operation |
Planner | Loader materializer/cancellation branch | Immutable StringName |
One call |
| Output | Selected index | Planner | Loader Resource array access | Integer value | One operation |
| Output | Next mesh and MultiMesh cursors | Planner | Loader job adoption | Fresh Dictionary values | Until adopted/discarded |
The planner retains no input or output. Scene-tree mutation, material refresh, job writes, permit consumption and cancellation are loader side effects.
Data flow
flowchart TD
Input[Counts and cursors] --> MeshRemaining{mesh index < mesh count?}
MeshRemaining -->|yes| MeshStep[mesh at mesh index; increment mesh cursor]
MeshRemaining -->|no| MultiRemaining{MultiMesh index < MultiMesh count?}
MultiRemaining -->|yes| MultiStep[MultiMesh at its index; increment MultiMesh cursor]
MultiRemaining -->|no| Complete[complete; keep both cursors]
Lifecycle/state
The planner is stateless. State belongs to the loader job. Repeated loader calls
advance through mesh steps, then multimesh steps, then complete. Planner
construction, cancellation, map reset and shutdown require no cleanup.
Main sequence
sequenceDiagram
participant Loader as StreamingWorldLoader
participant Planner as WmoRenderBuildStepPlanner
participant Scene as SceneTree
participant Budget as RenderBudgetScheduler
Loader->>Planner: plan_step(counts, cursors)
Planner-->>Loader: operation, selected index, next cursors
alt mesh or MultiMesh
Loader->>Loader: refresh material and create group Node
Loader->>Scene: attach Node and editor owner
Loader->>Loader: adopt returned cursor
Loader->>Budget: consume one WMO group permit
else complete
Loader->>Loader: cancel/remove job and queue key
end
Ownership, threading and resources
- The planner owns only call-local scalar comparisons and the returned value map.
WmoRenderBuildQueueowns typed jobs, FIFO keys and strong Node3D/Resource references. The loader owns mesh-array interpretation and engine lifetime.- The loader creates and owns every MeshInstance3D/MultiMeshInstance3D and performs material refresh and editor-owner assignment on the main thread.
RenderBudgetSchedulerowns permits; the planner neither reads nor consumes one.- Pure calls are thread-safe because the planner has no mutable state.
Errors, cancellation and recovery
| Failure/state | Detection | Behavior | Diagnostic | Recovery |
|---|---|---|---|---|
| Empty arrays | Both 0 < 0 comparisons false |
Return complete |
Contract verifier | Loader removes job |
| Cursor at/beyond count | Raw integer comparison | Skip that range | Contract verifier | Continue next range or complete |
| Negative cursor/count | Raw historical comparison | No clamp; select exactly as prior loader condition | Edge fixture | Caller should maintain valid job cursors |
| Missing/invalid Resource | Loader validation before planning | Loader cancels job | Existing shutdown/runtime diagnostics | Reload/requeue placement |
| Root freed | Loader validity check before planning | Loader cancels job | Runtime-cache shutdown verifier | Placement may rebuild later |
| Placement final release | Loader/registry lifecycle | Loader cancels queued build | Registry regression | Later placement starts at cursor zero |
Configuration and capabilities
The planner has no setting or profile branch. wmo_render_group_ops_per_tick,
quality presets, shadow/visibility settings and cache limits remain loader-owned.
Persistence, cache and migration
No data is persisted. WMO render resource format/version, cache path and job Dictionary fields are unchanged. No migration or cache rebuild is required.
Diagnostics and observability
The planner emits no logs. Its verifier reports operation/cursor/source contracts and bounded timing. Queue lengths, active WMO count and hitch sections remain in existing loader/facade diagnostics.
Verification
verify_wmo_render_build_step_planner.gd: mesh-first order, cursor increments, completion, empty and raw negative integer behavior, fresh results, loader delegation, dependency boundary and 20,000-plan timing.- WMO registry/resolver/material/shutdown plus renderer regressions verify the unchanged ownership and surrounding runtime path.
- Fidelity evidence is exact extraction of existing mesh-before-MultiMesh and one-index-per-permit behavior. No asset-backed build-12340 visual claim is made.
Extension points
WmoRenderBuildQueuenow owns typed pending state; cache/load requests and materialization remain separate extraction seams.- Materialization can later receive typed commands without changing this planner.
Capability status
| Capability | Status | Evidence | Gap/next step |
|---|---|---|---|
| WMO render build step planning | Implemented | Pure contract/source/timing verifier | Asset-backed traversal p95/p99 pending |
| WMO build job/queue ownership | Implemented | Typed lifecycle/source/timing verifier | Asset-backed traversal/leak evidence pending |
| WMO visual/portal/material fidelity | Partial | Renderer baseline/material checks | Original-client paired evidence pending |
Known gaps and risks
- Loader build jobs remain untyped Dictionaries.
- Resource array shape/length consistency remains a cache-builder invariant.
- No proprietary WMO corpus, traversal profile or paired client capture is part of this extraction.
Source map
| Path | Responsibility |
|---|---|
src/render/wmo/wmo_render_build_step_planner.gd |
Pure operation and cursor selection |
src/render/wmo/wmo_render_build_job.gd |
Typed engine references and cursors |
src/render/wmo/wmo_render_build_queue.gd |
Pending jobs, FIFO keys and cancellation state |
src/scenes/streaming/streaming_world_loader.gd |
Resource validation, materialization, permits and engine lifetime |
src/tools/verify_wmo_render_build_step_planner.gd |
Contract, boundary and timing regression |