9.5 KiB
WMO Placement Registry
Metadata
| Field | Value |
|---|---|
| Status | Implemented extraction |
| Target/work package | M03 / M03-RND-WMO-PLACEMENT-REGISTRY-001 |
| Owners | WMO placement-key to tile/global reference-set ownership |
| Last verified | Worktree work/sindo-main-codex/m03-wmo-placement-registry, 2026-07-17 |
| Profiles/capabilities | Existing ADT/WDT WMO placement paths; profile-independent |
Purpose
Own the reference sets that keep one resolved WMO placement active across one or more ADT tiles, or across the global WDT placement lifetime. This separates value-only placement ownership from scene and render-resource ownership.
Non-goals
- Resolve WMO paths, placement identity or world transforms.
- Own Nodes, Resources, RIDs, roots, jobs, queues, tasks or caches.
- Load, instantiate, build or free WMO content.
- Change duplicate order, budgets, retries or global-WMO behavior.
- Claim original-client WMO visual, portal, room or material parity.
Context and boundaries
flowchart LR
Parsed[ADT/WDT placement] --> Resolver[WmoPlacementResolver]
Resolver --> Key[Placement key]
Tile[Tile/global reference key] --> Loader[StreamingWorldLoader]
Key --> Loader
Loader --> Registry[WmoPlacementRegistry]
Registry --> Decision[Existing or final-release decision]
Decision --> Loader
Loader --> NodeMap[Loader key-to-Node map]
Loader --> Jobs[Loader jobs/queues/resources]
The registry depends only on RefCounted, Dictionary, Array and String.
SceneTree, Node, Resource, RID, files, loaders, threads, locks, network,
gameplay and editor UI are forbidden dependencies.
Public API
| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|---|---|---|---|---|
add_reference(placement_key, reference_key) |
Command/query | Idempotently add a reference; return true only when creating the placement key | Renderer main thread; map session | Empty key returns false and changes nothing |
release_reference(placement_key, reference_key) |
Command/query | Remove an owned reference; return true only on final removal | Renderer main thread; map session | Empty, unknown or non-owner input returns false |
contains(placement_key) |
Query | Test whether any reference keeps a placement active | Renderer main thread; map session | Empty key returns false |
active_count() |
Query | Count active placement keys, not references | Renderer main thread; map session | None |
diagnostic_snapshot() |
Query | Return detached, placement/reference-sorted records | Renderer main thread; caller-owned result | None |
clear() |
Command | Remove all ownership records idempotently | Renderer main thread; reset/shutdown | None |
Inputs and outputs
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|---|---|---|---|---|---|
| Input | Resolved uid:*, tile:*:* or global placement key |
WmoPlacementResolver / loader global adapter |
Registry | Copied String dictionary key | Until final release/clear |
| Input | ADT tile key or __global__ reference key |
Loader | Registry | Copied String set key | Until release/clear |
| Output | First-placement Boolean | Registry | Loader creation path | Value | One call |
| Output | Final-release Boolean | Registry | Loader cancellation/free path | Value | One call |
| Output | Active count and sorted diagnostic records | Registry | Renderer diagnostics/verifier | Detached values | Caller lifetime |
Data flow
flowchart TD
Add[add placement + reference] --> Valid{Both non-empty?}
Valid -->|no| Reject[false; unchanged]
Valid -->|yes| Existing{Placement exists?}
Existing -->|no| Create[Create reference set; true]
Existing -->|yes| Retain[Idempotently add reference; false]
Release[release placement + reference] --> Owner{Known owner reference?}
Owner -->|no| Reject
Owner -->|yes| Erase[Erase reference]
Erase --> Empty{Set empty?}
Empty -->|no| Retained[false; placement remains]
Empty -->|yes| Final[Erase placement; true]
Lifecycle and state
The states for one placement are Absent, Referenced and back to Absent.
The first valid add enters Referenced; further tile/global adds remain there.
Only release of the final owned reference returns to Absent. Map reset and
shutdown call clear, which is safe from either state.
stateDiagram-v2
[*] --> Absent
Absent --> Referenced: first valid add / true
Referenced --> Referenced: idempotent/shared add / false
Referenced --> Referenced: non-owner/non-final release / false
Referenced --> Absent: final owned release / true
Referenced --> Absent: clear
Main sequence
sequenceDiagram
participant Loader as StreamingWorldLoader
participant Registry as WmoPlacementRegistry
participant Nodes as Loader Node map
Loader->>Registry: contains(placement key)
alt existing placement
Loader->>Registry: add_reference(key, tile)
else new placement built successfully
Loader->>Nodes: store key-to-Node
Loader->>Registry: add_reference(key, tile/global)
end
Loader->>Registry: release_reference(key, tile)
alt final reference
Registry-->>Loader: true
Loader->>Loader: cancel render build
Loader->>Nodes: queue-free and erase Node
else shared/unknown reference
Registry-->>Loader: false
end
Ownership, threading and resources
- The registry owns only placement-key Dictionaries and reference-key sets.
- The loader owns the parallel placement-key-to-Node map and every Node action.
- The loader also owns WMO roots, tile state, caches, requests, jobs, queues, retries, cancellation and render-resource lifetime.
- Current calls are serialized on the renderer main thread. The registry has no lock and must not be mutated concurrently.
Errors, cancellation and recovery
| Failure | Detection | Behavior | Diagnostic | Recovery |
|---|---|---|---|---|
| Empty placement/reference key | API guard | Reject without mutation | Contract verifier | Repair caller input |
| Duplicate add | Existing set member | Idempotent retain | Sorted snapshot | No recovery required |
| Unknown/non-owner release | Missing placement/reference | Ignore without mutation | Contract verifier | Release from actual owner or reset |
| Tile build cancellation | Loader-owned condition | Loader cancels job, then releases recorded refs | Existing queue metrics | Retry when tile becomes wanted |
| Final release | Empty set after erase | Return true and erase registry record | Active count | Loader cancels/free Node exactly once |
| Map reset/shutdown | Loader lifecycle | Loader frees Nodes/jobs and clears registry | Shutdown regression | Next map begins empty |
Configuration and capabilities
There is no setting, profile branch or capacity knob. WMO tile radius, cache limits, render budgets and visibility settings remain loader-owned.
Persistence, cache and migration
No data is serialized and no cache/schema/version changes. Placement and reference keys exist only for the current renderer map session.
Diagnostics and observability
active_count backs existing WMO instance metrics. diagnostic_snapshot
returns deterministic detached records for tests and future read-only
diagnostics; mutating the returned arrays cannot alter registry state.
Verification
verify_wmo_placement_registry.gd: invalid/first/idempotent/shared/non-owner/ final/global/clear behavior, deterministic detached diagnostics, source ownership boundaries and bounded 100-by-256 shared-reference cycles.- WMO resolver, material, runtime-cache shutdown and the renderer regression suite verify the unchanged loader adapters and surrounding lifecycle.
- Fidelity evidence is exact preservation of the repository's prior shared-ref and final-release semantics. Asset-backed 3.3.5a comparison is still pending.
Extension points
- WMO build/resource state can be extracted separately without moving Nodes into this registry.
- A future diagnostic adapter may expose the detached snapshot through the facade without exposing mutable loader internals.
Capability status
| Capability | Status | Evidence | Gap/next step |
|---|---|---|---|
| WMO placement reference ownership | Implemented extraction | Contract/source/timing verifier | Asset-backed cross-tile corpus pending |
| WMO build/resource scheduling | Remains in loader | Existing runtime regressions | Separate state/cancellation package |
| WMO visual/portal/material fidelity | Partial | Renderer baseline/material checks | Original-client paired evidence pending |
Known gaps and risks
- Correctness assumes the loader records each successful placement reference in
the tile
wmo_refsarray before unregister. - Old caches without positive UID retain resolver-defined per-tile identity.
- No proprietary WMO corpus or original-client paired capture is in this package.
Source map
| Path | Responsibility |
|---|---|
src/render/wmo/wmo_placement_registry.gd |
Placement-key/reference-set ownership |
src/render/wmo/wmo_placement_resolver.gd |
Stable path, identity and transform rules |
src/scenes/streaming/streaming_world_loader.gd |
Node map, instances, resources, jobs, queues and lifecycle reactions |
src/tools/verify_wmo_placement_registry.gd |
Contract, boundary and timing regression |