# World Renderer ## Metadata | Field | Value | |---|---| | Status | Partial | | Target/work package | M00 baseline; `M01-RND-STREAMING-FOCUS-001`; `M01-QAR-SERVER-SPAWN-RENDERER-001`; `M03-RND-FACADE-001`; `M03-RND-STREAMING-PLANNER-001`; `M03-RND-SCHEDULER-001`; `M03-RND-INTERNAL-ACCESS-GATE-001`; `M03-RND-FACADE-GROUND-QUERY-001`; `M03-RND-FACADE-ENVIRONMENT-001`; `M03-RND-FACADE-ENTITY-001` | | Owners | Renderer workstream / milestone integrator | | Last verified | Worktree `work/sindo-main-codex/m03-facade-entity`, 2026-07-16 | | Profiles/capabilities | `Performance`, `Balanced`, `High`, `Custom`; Blizzlike fidelity incomplete | ## Purpose Загрузить и визуализировать мир WoW 3.3.5a вокруг streaming focus: terrain, ADT placements, M2, WMO, liquids, sky/light и character/world presentation experiments. Система должна скрывать I/O/parsing/finalization latency за prewarm и per-frame budgets. ## Non-goals - Не владеет gameplay/world authoritative state. - Не читает network packets или server DB. - Не определяет player input/movement rules. - Не является Content Project или editor source of truth. - Текущий module не заявляет визуальное соответствие `1:1`; gaps ведутся в [`../../RENDER.md`](../../RENDER.md). ## Context and boundaries ```mermaid flowchart LR Player[Player or spectator Node3D] --> Adapter[Explicit source adapter] Editor[Editor viewport adapter] --> Focus[StreamingFocus] Capture[Capture tool] --> Adapter SpawnFixture[Pinned server spawn fixture] --> SpawnManifest[Spawn render manifest] SpawnManifest --> Capture Adapter --> Focus Focus --> Facade[WorldRenderFacade] Facade --> Loader[StreamingWorldLoader internal] Loader --> Planner[StreamingTargetPlanner] Planner --> TargetPlan[StreamingTargetPlan] TargetPlan --> Loader Loader --> Budget[RenderBudgetScheduler] Assets[Extracted WDT/ADT/M2/WMO/BLP] --> Native[Native loaders] Cache[Baked terrain/M2/WMO caches] --> Loader Native --> Parsed[Parsed tile/model data] Parsed --> Loader Loader --> Scene[SceneTree nodes] Loader --> RS[RenderingServer RIDs/MultiMesh] EnvironmentState[World time producer] --> EnvironmentSnapshot[WorldEnvironmentSnapshot] EnvironmentSnapshot --> Facade Facade --> SkyController[WowSkyController] Sky[DBC sky/light data] --> SkyController SkyController --> Scene EntityState[Entity visual read model] --> EntitySnapshot[EntityPresentationSnapshot] EntitySnapshot --> Facade Facade --> EntityPresenter[WorldEntityPresenter] EntityPresenter --> Scene ``` Allowed dependencies: - native format loaders; - render builders/material helpers; - immutable/cached render resources; - renderer configuration and focus; - Godot rendering/scene APIs. Forbidden dependencies: - packet codecs/world session; - gameplay reducers/quest/combat state; - runtime UI Controls; - direct TrinityCore/AzerothCore database access. ## Public API Runtime, capture and probe callers use `WorldRenderFacade` for focus, immutable environment/entity presentation input, metrics and rendered-ground diagnostics. `StreamingWorldLoader`, `WowSkyController` and `WorldEntityPresenter` remain internal scene implementations. Gameplay modules and Godot `EditorPlugin` package sources are repository-gated from externally reading/writing loader-private queue, task, cache and tile-state fields. | Symbol | Kind | Purpose | Thread/lifetime | Errors | |---|---|---|---|---| | `map_name` | Exported property | WDT/map directory name | Set before world load | Missing WDT produces diagnostic/empty world | | `extracted_dir` | Exported property | Root of legally extracted client data | Session lifetime | Missing files reported per loader path | | `StreamingFocus` | Immutable value | Typed Godot-basis position without Node/Camera dependency | Any thread; caller-owned reference | Null position is a caller contract violation | | `WorldRenderFacade.streaming_focus_source_path` | Exported adapter property | Samples any explicit `Node3D` source into `StreamingFocus` | Main thread, scene lifetime | Missing/wrong node warns once and retains prior focus | | `WorldRenderFacade.set_streaming_focus` | Public method | Accepts focus from app/editor/tool composition | Main thread/session | Missing internal renderer is diagnosed; no state is duplicated | | `WorldRenderFacade.refresh_streaming_focus` | Public method | Samples configured source and delegates existing refresh thresholds | Main thread/session | Returns `false` when dependency/focus is unavailable | | `WorldRenderFacade.renderer_metrics_snapshot` | Public method | Returns a deep-detached queue/cache/activity snapshot | Main thread/caller-owned result | Missing/invalid implementation result returns empty snapshot with diagnostic | | `WorldRenderFacade.sample_ground_height` | Public read-only query | Samples already loaded render terrain at a typed Godot world position | Main thread; immutable caller-held result | Stable unavailable code for missing mesh/intersection/facade; not gameplay authority | | `WorldRenderFacade.renderer_ground_query_snapshot` | Public diagnostic query | Returns ground height plus detached tile/readiness context without exposing mutable state | Main thread; caller-owned deep copy | Missing/invalid renderer returns empty snapshot with diagnostic | | `WorldEnvironmentSnapshot.at_time_of_day` | Immutable value factory | Normalizes a finite authoritative time into `[0, 24)` hours | Any thread; caller-held value | Non-finite input creates invalid value with `environment_time_not_finite` | | `WorldRenderFacade.apply_environment_snapshot` | Public command | Delegates exact world time to the scene-owned DBC sky controller | Main thread; snapshot remains caller-owned | Returns `false` for invalid input or missing/incompatible controller | | `WorldRenderFacade.streaming_world_loader_path` | Internal adapter property | Resolves the existing implementation without exposing it to consumers | Main thread, scene lifetime | Missing method/path produces one diagnostic until recovery | | `WorldRenderFacade.world_environment_controller_path` | Internal adapter property | Resolves the existing `WowSkyController` without exposing it to consumers | Main thread, scene lifetime | Missing method/path produces one diagnostic until recovery | | `EntityPresentationSnapshot.create` | Immutable value factory | Validates contract-v1 identity, typed position, visual path, yaw, scale and visibility | Any thread; caller-owned | Stable invalid code; never mutates scene | | `WorldRenderFacade.present_entity` | Public command | Idempotently creates/updates/replaces one session entity visual | Main thread/session | Returns false for invalid input, missing service or visual load/type failure | | `WorldRenderFacade.remove_entity` | Public command | Removes one known session entity visual | Main thread/session | Invalid/unknown identity returns false | | `WorldRenderFacade.entity_presentation_snapshot` | Public diagnostic query | Returns detached scalar entity inventory | Main thread/caller-owned copy | Missing/invalid service returns empty dictionary with diagnostic | | `WorldRenderFacade.world_entity_presenter_path` | Internal adapter property | Resolves renderer-owned entity visual service | Main thread/scene lifetime | Missing methods/path produces one diagnostic until recovery | | `camera_path` | Exported property | Camera used only by optional automatic overview positioning | Main thread, scene lifetime | Missing camera skips automatic positioning | | `quality_preset` | Exported property | Applies renderer budgets/radii | Before/at runtime depending property | Invalid combination should be diagnosed | | `runtime_stats_enabled` | Exported property | Enables periodic performance snapshot | Runtime mutable | Logging overhead only | | `hitch_profiler_enabled` | Exported property | Enables named hitch sections | Runtime mutable | Logging overhead only | Публичным contract не считаются `StreamingWorldLoader` methods/properties, внутренние dictionaries, queues, job records и generated node names. Scene-owned loader configuration remains transitional composition data, not a caller API. ## Inputs and outputs | Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime | |---|---|---|---|---|---| | Input | `StreamingFocus` | Player/spectator/editor/capture adapter | `WorldRenderFacade` | Immutable caller value | Main thread/session | | Input | Focus-source `NodePath` | Runtime/test scene composition | `WorldRenderFacade` source adapter | Scene-owned node, sampled position | Main thread/scene lifetime | | Input | Ground-query `GodotWorldPosition` | Renderer probe/future adapter | `WorldRenderFacade` | Immutable caller-held value | One main-thread query | | Input | `WorldEnvironmentSnapshot` | World-state/capture adapter | `WorldRenderFacade` / `WowSkyController` | Immutable caller-held value; not retained | One main-thread update | | Input | `EntityPresentationSnapshot` | Future world-state/preview adapter | `WorldRenderFacade` / entity presenter | Immutable caller-held full visual snapshot | One main-thread present/update | | Input | `EntityId` removal command | Future entity registry/adapter | `WorldRenderFacade` / entity presenter | Immutable session-local value | One main-thread removal | | Input | Map/configuration | Scene/app/editor | `StreamingWorldLoader` | Caller config, copied/read | Main thread/session | | Input | WDT/ADT/M2/WMO/BLP bytes | Extracted asset repository | Native loaders/builders | Loader result owns parsed data | Worker or controlled load | | Input | Baked resources | Cache build tools | Streamer/builders | Shared immutable resource/cache entry | Session/cache lifetime | | Test input | Server-spawn render manifest | Coordinate fixture/verifier | Checkpoint capture tool | Repository-owned diagnostic data | Test-process lifetime | | Output | `StreamingTargetPlan` | `StreamingTargetPlanner` | Streamer queue/state apply | Immutable ephemeral value | One refresh | | Internal control | Per-frame lane limits and boolean permits | Streamer configuration / `RenderBudgetScheduler` | Ordered streamer drains | Scheduler-owned counters | Main thread/frame | | Output | Desired tile/detail operations | Streamer plan application | Finalize queues | Loader-owned | Cross-frame | | Output | Terrain/M2/WMO/liquid instances | Loader/builders | Godot world/renderer | Loader/world owner | Main-thread attach | | Output | Detached renderer metrics | `WorldRenderFacade` | Capture/baseline tools | Caller-owned deep copy | On demand | | Output | `RenderedGroundSample` | `WorldRenderFacade`/loaded terrain | Renderer diagnostics | Immutable caller-held value | One query | | Output | Detached rendered-ground snapshot | `WorldRenderFacade` | Terrain-height probe | Caller-owned deep copy | One query | | Output | Entity visual Node3D subtree | `WorldEntityPresenter` | SceneTree/viewport | Presenter-owned child | Until replace/remove/teardown | | Output | Detached entity inventory | `WorldRenderFacade` | Diagnostics/tests | Caller-owned deep copy | One query | | Output | Logs/diagnostics | Hitch/stat instrumentation | Logs/baseline tools | Immutable records | Periodic/frame | | Test output | Diagnostic spawn marker and cold/warm PNGs | Checkpoint capture tool | Human/integrator review | SceneTree marker; `user://` files | One capture process | Side effects: - reads extracted files and generated caches; - creates/frees scene nodes, meshes, materials, MultiMeshes and RIDs; - submits worker tasks; - mutates shader globals/environment through render/sky paths; - writes logs and baseline captures through tools. ## Data flow ```mermaid flowchart TD PlayerSource[Player/spectator Node3D] --> A[Explicit scene adapter] C[Capture camera] --> A SF[Pinned server spawn] --> SM[Validated spawn manifest] SM --> C SM --> Marker[Renderer-native origin marker] E[Editor viewport] --> EA[Editor adapter] A --> F[StreamingFocus] EA --> F F --> RF[WorldRenderFacade] RF --> Planner[StreamingTargetPlanner] Planner --> T[StreamingTargetPlan apply] WDT[WDT tile catalog] --> Planner T --> Q[Tile load queue] Q --> Parse[Worker parse/cache load] Parse --> R[Result queues] R --> B[RenderBudgetScheduler permits] B --> Terrain[Terrain attach/upgrade] B --> M2[M2 group/MultiMesh attach] B --> WMO[WMO instance/group attach] B --> Liquid[Liquid attach] Loaded[Loaded terrain Mesh and Transform] --> Ground[Facade ground query] Ground --> GroundSample[RenderedGroundSample / detached diagnostics] WorldTime[Authoritative/test time] --> EnvironmentSnapshot[WorldEnvironmentSnapshot] EnvironmentSnapshot --> RF RF --> SkyController[WowSkyController] DBC[Light/Area/Skybox DBC] --> SkyController SkyController --> World EntityReadModel[Entity visual read model] --> EntitySnapshot[EntityPresentationSnapshot] EntitySnapshot --> RF RF --> EntityPresenter[WorldEntityPresenter] EntityAsset[PackedScene path] --> EntityPresenter EntityPresenter --> World Terrain --> World[Godot world] M2 --> World WMO --> World Liquid --> World Marker --> World F --> Eviction[Eviction/retention decisions] Eviction --> World ``` ## Lifecycle/state ```mermaid stateDiagram-v2 [*] --> Initializing Initializing --> WaitingForFocus: WDT/catalog/config ready Initializing --> Degraded: missing loaders/data/cache WaitingForFocus --> Streaming: valid StreamingFocus Streaming --> Streaming: load/finalize/evict ticks Streaming --> WaitingForFocus: world reset without replacement focus Streaming --> SwitchingMap: map/focus reset SwitchingMap --> Initializing WaitingForFocus --> ShuttingDown Degraded --> ShuttingDown Streaming --> ShuttingDown ShuttingDown --> [*] ``` ## Main sequence ```mermaid sequenceDiagram participant Source as Player/Editor/Capture source participant Focus as StreamingFocus adapter participant Facade as WorldRenderFacade participant Stream as StreamingWorldLoader internal participant Planner as StreamingTargetPlanner participant Worker as Worker task participant Budget as RenderBudgetScheduler participant Render as SceneTree/RenderingServer Source->>Focus: sample explicit Godot position Focus->>Facade: set/refresh typed focus Facade->>Stream: delegate focus and refresh Stream->>Planner: typed focus, catalog and target policy Planner-->>Stream: immutable wanted/retained plan Stream->>Stream: queue priority and loaded-tile LOD/detail state Stream->>Worker: parse/load tile and detail data Worker-->>Stream: immutable result Stream->>Budget: begin_frame(operation limits) Stream->>Budget: try_consume_permit(lane) Budget-->>Stream: true while lane remains bounded Stream->>Render: attach permitted terrain/M2/WMO/liquid work Stream->>Render: evict outside retention range Source->>Facade: sample_ground_height(typed position) Facade->>Stream: sample loaded render terrain Stream-->>Facade: RenderedGroundSample / diagnostic snapshot Source->>Facade: apply_environment_snapshot(exact time) Facade->>Render: delegate to WowSkyController Render->>Render: freeze local clock; retain DBC sampling/apply rules Source->>Facade: present_entity(full visual snapshot) Facade->>Render: delegate to WorldEntityPresenter Render->>Render: create/update/replace owned entity root Source->>Facade: remove_entity(EntityId) Facade->>Render: detach and queue_free owned root Stream->>Budget: shutdown: cancel permit issuance Stream->>Worker: shutdown: wait for WorkerThreadPool tasks Stream->>Stream: shutdown: finish registered ResourceLoader requests Stream->>Render: clear queues and owned tree nodes/RIDs Stream->>Stream: free detached prototypes and release resource caches ``` ## Ownership, threading and resources - `StreamingWorldLoader` владеет tile states, queues, task registries, active world instances и render caches session scope. - `WorldRenderFacade` owns only scene-relative adapter paths. It does not own the streamer, environment controller, focus source, returned metrics, queues, caches, nodes or RIDs. - `WorldEnvironmentSnapshot` is an immutable caller-owned scalar value. Neither facade nor sky controller retains it; the controller copies normalized hours into its existing fixed-clock fields on the main thread. - `WowSkyController` continues to own DBC sampling state and mutations of its duplicated Godot `Environment`, sun, skybox node and world shader globals. - `WorldEntityPresenter` owns one optional visual Node3D subtree per presented `EntityId`; it owns no authoritative entity state and excludes the local player. - Entity presentation snapshots remain caller-owned inputs. Detached diagnostics expose only identity debug keys, paths and visibility, never Node/Resource/RID. - Rendered-ground query results and diagnostic snapshots are caller-owned values; the facade never returns Mesh, Node, tile-state or queue references. - Loaded-mesh ground sampling is renderer diagnostics, not authoritative gameplay collision. M02 `TerrainQuery` composition and ADT cache ownership remain unchanged. - `StreamingTargetPlanner` is stateless and owns only call-local calculations; its immutable plan is consumed synchronously by the streamer. - `RenderBudgetScheduler` owns only per-frame lane counters and a terminal cancellation flag. The streamer retains queue ordering and all operation side effects. - Focus producers own the immutable `StreamingFocus` reference; the loader retains the latest reference and converts it to `Vector3` only inside the render boundary. - Worker tasks не должны менять SceneTree и shared Resource concurrently. - Parsed/grouped results передаются обратно через guarded result queues. - Mesh/material/node/RID finalization выполняется main thread и ограничивается exported budgets. - Shutdown/map switch обязан дождаться WorkerThreadPool jobs и зарегистрированных threaded ResourceLoader requests до очистки очередей, nodes, caches и RIDs. - Parented streamed nodes остаются owned by SceneTree during shutdown; detached M2/WMO prototype caches are explicitly `free()`d after asynchronous work drains. - A temporary liquid root with no generated child geometry is explicitly freed by `ADTBuilder` instead of being returned or abandoned. - Cache resources считаются immutable после публикации. ## Errors, cancellation and recovery | Failure | Detection | Behavior | Diagnostic | Recovery | |---|---|---|---|---| | Missing WDT/ADT | File/catalog check | Tile/map unavailable | Loader warning/error | Fix extraction/profile, reload | | Missing focus source | Explicit NodePath resolution | Retain current streamed content and prior valid focus | One warning until source recovers | Fix composition path or call `set_streaming_focus` | | Missing renderer implementation | Facade path/method validation | Focus/metrics call fails without mutation | One facade diagnostic until recovery | Fix scene composition path/implementation | | Invalid metrics result | Facade return-type validation | Return empty caller snapshot | Facade error | Restore `Dictionary` implementation contract | | Invalid environment time | Snapshot finite-value validation | Reject update; retain prior sky clock | `environment_time_not_finite` on invalid value | Supply a finite time snapshot | | Missing environment controller | Facade path/method validation | Reject environment update; other facade APIs remain available | One facade diagnostic until recovery | Fix scene composition path/implementation | | Invalid entity visual snapshot | Contract validation | Reject without scene mutation | Stable `entity_presentation_*` failure code | Repair adapter read model and resend | | Missing/invalid entity visual asset | Resource existence/load/root check | New entity absent or prior replacement retained | Named presenter warning | Restore asset mapping and resend snapshot | | Missing entity presenter | Facade path/method validation | Reject entity commands; other facade APIs remain available | One facade diagnostic until recovery | Fix runtime scene composition | | No focus supplied | Refresh contract | No target recomputation; queues continue draining | `refresh_streaming_focus()` returns `false` | Supply player/editor/capture focus | | Cache version mismatch | Required format constant | Reject stale cache/fallback | Version diagnostic | Rebuild matching cache | | Worker failure | Task result/empty data | Skip/degrade affected asset | Queue/task warning | Retry/rebuild source | | Main-thread hitch | Named section timing | Frame spike, work remains queued | `HITCH` log | Lower budget/fix finalize path | | Render terrain unavailable | Facade ground query | Immutable unavailable sample | Stable `render_terrain_*` failure code and optional snapshot | Wait for streaming or use gameplay-owned query backend | | D3D12 descriptor exhaustion | Rendering backend error | Render failure/fallback backend | Godot error + baseline report | Dedup resources/fix settings | | Teleport/map change | Focus/session transition | Old jobs become stale | Target/session generation | Cancel/drop stale results | | Shutdown leak | Godot leak/RID diagnostics | Resource retained | Verbose shutdown report + cache shutdown verifier | Drain requests, preserve tree ownership, then free detached prototypes and clear resource caches | ## Configuration and capabilities | Setting/capability | Default | Profile | Runtime mutable | Effect | |---|---|---|---|---| | Quality preset | Scene-specific | All | Limited | Applies radii and finalize budgets | | Terrain control splat | Enabled in current High paths | Render | Limited | Near terrain texture quality | | M2/WMO/liquids | Scene/profile-specific | Render | Debug/config | Enables asset categories | | Runtime stats/hitch profiler | Usually debug | Dev/test | Yes | Observability cost | | Shadow flags | Mostly disabled/limited | Blizzlike/Enhanced | Profile | CPU/GPU cost and visuals | Exact exported settings and cache versions remain documented in [`../../RENDER.md`](../../RENDER.md) until extracted services receive individual specs. ## Persistence, cache and migration - `StreamingFocus` is runtime-only and is not serialized. Scene migration adds `streaming_focus_source_path`; existing `camera_path` remains valid only for optional automatic overview positioning. - Renderer reads caches under `data/cache`; caches are not committed. - Format changes require `FORMAT_VERSION`/required-version bump and rebuild instructions. - Atomic cache publication and unified manifest are target-state work from FND/M03. - Material-only changes may refresh without geometry rebake only when documented safe. ## Diagnostics and observability - Logs: `HITCH`, `PERF`, `TERRAIN_QUALITY`, `SKY_LIGHT`, `SKYBOX_MODEL`. - API snapshot: `WorldRenderFacade.renderer_metrics_snapshot()` returns detached queue/cache/activity counts without exposing mutable renderer state. - Metrics: queue depths, active tiles/assets, named finalize times, frame percentiles and max hitch. - Debug views: render checkpoint scenes/captures; future streaming/LOD/portal overlays. - Correlation IDs: currently mostly tile/path keys; target architecture adds session/job IDs. ## Verification - Unit/contract tests: streaming-focus contract/wiring, material mapping, unique-ID dedupe, placement probes, baseline manifest, five-point coordinate calibration, synthetic perceptual checkpoint diff, camera-pose grid plan. - Pure planner contract: center/corner/catalog/clamp/editor cases plus bounded High-like iteration timing without loading a world scene. - Budget scheduler contract: exact lane exhaustion, shared chunk removal/create priority, independent lanes, frame reset, invalid limits, terminal cancellation, dependency boundaries and bounded permit timing without loading a world scene. - Internal-access contract: derives the current streamer's private queue/task/ cache/state field inventory and rejects external member/reflection access from gameplay or EditorPlugin package code. - Ground-query facade contract: available/unavailable typed result delegation, detached nested diagnostics and terrain-probe source migration without private access. - Rendered-ground value contract: available/non-finite/unavailable invariants pass from a cold Godot class cache before editor import. - Integration/E2E: Eastern Kingdoms/Kalimdor streaming scenes, seven M00 cold/warm checkpoints and one dedicated mapped server-spawn checkpoint. - Fidelity evidence: семь локальных build 12340 reference JPG покрывают terrain/ADT/M2/WMO/liquid/sky и реальный `GryphonRoost01`; automated cold/warm metrics имеют `compared=14`, `missing=0`. Sky использует приблизительно paired camera, а animated-M2 остаётся asset-paired/placement-unpaired из-за synthetic probe. - Performance budgets: M00 report records cold/warm p95 and max hitch; no final acceptance threshold yet. - Manual diagnostics: [`../RENDER_BASELINE.md`](../RENDER_BASELINE.md) and [`../../RENDER.md`](../../RENDER.md). ## Extension points - Target `WorldRenderFacade` for runtime/editor/capture callers. - Extend `StreamingFocus` with measured direction/velocity needs when the pure planner is extracted. - Extracted planner, budget scheduler, terrain, M2, WMO, liquid, sky and character services. - Separate Blizzlike/Enhanced material and quality profiles. ## Capability status | Capability | Status | Evidence | Gap/next step | |---|---|---|---| | ADT streaming/terrain | Partial | M00 checkpoints and current scenes | Fidelity/performance gaps remain | | Static M2 placement | Partial | MultiMesh/dedupe probes | Full materials/animation/effects | | WMO rendering | Partial | Cached group rendering | Portals/rooms/material parity | | Liquids | Partial | MH2O/MLIQ paths | LiquidType/depth/shore fidelity | | Sky/light | Partial | DBC controller/logs | Zone transition paired validation | | Character presentation | Prototype | Character creator/player experiment | Full customization/equipment states | | Camera-independent streaming focus | Implemented | Typed contract, two player-focused runtime scenes and three explicitly camera-focused diagnostic tools | Multi-focus/direction/velocity belong to planner extraction | | Golden server-spawn visualization | Implemented | Pinned AzerothCore fixture, validated renderer manifest and diagnostic origin-marker capture at ADT `(32,48)`/MCNK `(3,12)` | No TrinityCore row or original-client visual-parity claim | | Stable renderer facade | Implemented boundary / Partial fidelity | Facade contracts cover focus, environment, entity visuals, metrics and loaded-mesh ground query | Production consumers and fidelity remain | | Environment snapshot input | Implemented boundary / Partial fidelity | Immutable time contract, facade/controller delegation and checkpoint migration | Weather/indoor state and paired zone-transition fidelity remain | | Entity presentation commands | Implemented boundary / Prototype visuals | Versioned typed snapshot plus present/remove lifecycle and runtime service composition | Display/equipment/animation/effects and async scale path remain | | Pure streaming target planner | Implemented | `M03-RND-STREAMING-PLANNER-001` asset-free contract/performance regression | Queue scheduling and loaded-tile LOD application remain in streamer | | Bounded render budget scheduler | Implemented | `M03-RND-SCHEDULER-001` asset-free permit/cancellation/performance regression | Queue storage, worker concurrency and operation execution remain in streamer/services | | Gameplay/editor/tool internal-access boundary | Implemented | Access gate scans gameplay, EditorPlugin packages and terrain probe against actual private streamer declarations | Add future renderer diagnostic tools explicitly to the protected list | | Rendered terrain ground query | Implemented | `M03-RND-FACADE-GROUND-QUERY-001` typed result/snapshot isolation and probe migration | Diagnostic Mesh ray only; not movement/collision authority | ## Known gaps and risks - Monolithic streamer mixes planning, jobs, caches and presentation. - `camera_path` remains only for optional automatic overview positioning; it no longer drives runtime streaming or discovers the active viewport camera. - Original-client paired fidelity evidence incomplete. - Первый paired run выявил coordinate/placement mismatch: несколько совпадающих server-derived camera positions оказываются под terrain или внутри WMO/rocks OpenWC. - Terrain-height probe исключил under-terrain состояние для всех пяти точек; waterfall exact-XZ miss классифицирован как TriangleMesh seam/edge и подтверждён nearby sample в 2 units. - Camera-occluder probe не нашёл camera containment в пяти точках; paired mismatch локализован прежде всего в manual look direction/target/FOV calibration, с явным ограничением по RID-only geometry. - Empirical FOV sweep выявил, что checkpoint camera должна явно вызывать `make_current()`; после исправления projection ranking остаётся inconclusive из-за неизвестного manual yaw/pitch/framing reference. - Camera-pose sweep can now rank bounded yaw/pitch grids without changing manifest defaults; perceptual ranking remains diagnostic and requires human framing approval. - The first Goldshire pose grid was invalidated by WMO readiness: the inn is absent after 2 seconds but visible after the manifest-standard 8-second wait. Pose comparisons must stabilize asynchronous checkpoint content first. - A ready-scene Goldshire 3x3 grid improved mean error from `0.101402` at zero offsets to `0.087952` at yaw `10`/pitch `-10`; pitch/FOV refinement remains required before manifest calibration. - Joint Goldshire pitch/FOV refinement had no human-approved optimum: full-frame error preferred grass-heavy FOV 62/pitch -25, while FOV 38/pitch -10 better matched building scale. Landmark/region scoring is required before calibration. - Common-region scoring `[300,100,1400,650]` moved Goldshire's numeric optimum to FOV 38/yaw 10/pitch -15, but human inspection still found an oversized/cropped facade; semantic landmarks or masks remain required. - Final paired audit compared fourteen cold/warm images for seven private build 12340 references with zero missing pairs; mean error ranges `0.066893..0.176955`. Animated-M2 native motion is observed across two original-client phases, but its real Lakeshire placement differs from the synthetic Goldshire probe. Sky-transition evidence uses the checkpoint map position/time with manually approved approximate framing. - D3D12 descriptor issues remain. Explicit shutdown ownership removes the GUI capture's Node/resource/RID leaks in focused and seven-checkpoint runs; a timing-dependent ObjectDB warning for anonymous zero-reference `RefCounted` objects remains as a separate engine-teardown diagnostic. - M2/WMO/material/particle/ribbon/portal parity incomplete. - Public API is mostly exported configuration rather than stable contracts. - Rendered-ground sampling generates a triangle mesh on demand and retains the historical nearby seam fallback. It is appropriate for diagnostics, not a per-physics-frame gameplay query or a claim of exact terrain collision parity. ## Source map | Path | Responsibility | |---|---| | `src/render/world_render_facade.gd` | Stable caller boundary for typed focus/environment, detached metrics and rendered-ground queries | | `src/render/environment/world_environment_snapshot.gd` | Immutable normalized world time input with explicit invalid state | | `src/render/entities/entity_presentation_snapshot.gd` | Immutable contract-v1 entity visual input and validation | | `src/render/entities/world_entity_presenter.gd` | Main-thread entity visual subtree ownership and lifecycle | | `src/render/terrain/rendered_ground_sample.gd` | Immutable renderer-owned available/unavailable ground query result | | `src/render/streaming/streaming_target_planner.gd` | Scene-free wanted/retained ADT target calculation | | `src/render/streaming/streaming_target_policy.gd` | Immutable renderer radius/prefetch policy | | `src/render/streaming/streaming_target_plan.gd` | Immutable planner result with read-only tile-key sets | | `src/render/streaming/render_budget_scheduler.gd` | Scene-free per-frame operation permits and terminal cancellation | | `src/scenes/streaming/streaming_world_loader.gd` | Current runtime orchestration, queues, caches and attachment | | `src/domain/streaming/streaming_focus.gd` | Immutable camera-independent streaming position contract | | `src/tools/verify_streaming_focus.gd` | Headless contract, dependency and runtime/tool wiring regression | | `src/tools/verify_world_render_facade.gd` | Focus/environment/metrics/ground delegation, snapshot isolation and consumer wiring regression | | `src/tools/verify_world_environment_snapshot.gd` | Cold-start environment value normalization and invalid-input regression | | `src/tools/verify_world_entity_presentation.gd` | Entity snapshot, create/update/replace/remove and ownership regression | | `src/tools/verify_rendered_ground_sample.gd` | Cold-start renderer ground result invariant regression | | `src/tools/verify_streaming_target_planner.gd` | Planner behavior, dependency and bounded timing regression | | `src/tools/verify_render_budget_scheduler.gd` | Scheduler bounds, shared-lane priority, cancellation and timing regression | | `src/tools/verify_renderer_internal_access.gd` | Gameplay/EditorPlugin/registered renderer-tool boundary gate derived from private streamer fields | | `addons/mpq_extractor/loaders/adt_builder.gd` | Terrain/material/liquid construction | | `addons/mpq_extractor/loaders/m2_builder.gd` | Static M2 mesh/material construction | | `addons/mpq_extractor/loaders/m2_native_animated_builder.gd` | Native animated M2 experiment | | `addons/mpq_extractor/loaders/wmo_builder.gd` | WMO groups/doodads/liquids construction | | `src/scenes/sky/wow_sky_controller.gd` | DBC-driven sky/light/environment | | `src/native/src/*_loader.cpp` | Native binary parsing | | `src/tools/build_*cache.gd`, `src/tools/bake_*cache.gd` | Offline cache generation | | `tools/run_render_baseline.ps1` | Unified M00 baseline runner | | `src/tools/compare_render_checkpoints.gd` | Offline JPG/PNG paired-image perceptual metrics and JSON pass/fail report | | `src/tools/verify_render_runtime_cache_shutdown.gd` | Headless ownership regression for detached runtime prototypes, resource caches and empty liquid roots | | `src/tools/capture_render_checkpoints.gd` | Deterministic no-roll checkpoint camera, performance and visual capture | | `src/tools/server_spawn_render_manifest.json` | Dedicated mapped AzerothCore spawn checkpoint and diagnostic marker configuration | | `src/tools/verify_server_spawn_renderer.gd` | Fixture-to-renderer checkpoint contract verification | | `tools/sweep_render_checkpoint_camera_pose.ps1` | Offline yaw/pitch capture grid and paired-error ranking | | `src/tools/verify_render_coordinate_calibration.gd` | Build 12340 camera-coordinate golden point round-trip diagnostic | | `src/tools/probe_render_terrain_height.gd` | Offline facade-backed active-mesh terrain height and camera-clearance report | | `src/tools/probe_render_camera_occluders.gd` | Scene-tree placement containment and camera-to-target AABB intersection report | ## Related decisions and references - [`../../RENDER.md`](../../RENDER.md) - [`../RENDER_BASELINE.md`](../RENDER_BASELINE.md) - [`../CAMERA_POSE_SWEEP.md`](../CAMERA_POSE_SWEEP.md) - [`../M00_FINAL_PAIRED_EVIDENCE.md`](../M00_FINAL_PAIRED_EVIDENCE.md) - [`../../targets/roadmap/02-rendering-and-graphics.md`](../../targets/roadmap/02-rendering-and-graphics.md) - [`../GODOT_BEST_PRACTICES.md`](../GODOT_BEST_PRACTICES.md)