Compare commits

...

5 Commits

14 changed files with 402 additions and 23 deletions
+14
View File
@@ -950,6 +950,20 @@ $exe = Join-Path $env:TEMP 'godot-4.6.1-openwc\Godot_v4.6.1-stable_win64.exe'
- The ray height, 3x3 tile search and `2/5/10/20/40`-unit nearby fallback are - The ray height, 3x3 tile search and `2/5/10/20/40`-unit nearby fallback are
preserved. No terrain geometry, cache, streaming or visual behavior changed. preserved. No terrain geometry, cache, streaming or visual behavior changed.
## 2026-07-16 World Environment Snapshot Facade
- `WorldEnvironmentSnapshot` carries one immutable finite time-of-day value,
normalized to `[0, 24)` hours; invalid non-finite input is explicit.
- `WorldRenderFacade.apply_environment_snapshot()` delegates the snapshot to the
scene-owned `WowSkyController`. The facade owns no `Environment`, sun, skybox,
shader global or DBC sampling state.
- Checkpoint capture now submits its manifest time through the facade instead of
locating `WowSkyController` and mutating `use_system_time`, `time_speed` and
`fixed_time_hours` directly.
- Applying a snapshot performs the same three fixed-clock assignments as the old
capture path. Light/Area/Skybox DBC lookup, interpolation, fog, sun and shader
behavior remain unchanged; weather and indoor environment state are follow-up work.
## Practical Rule For Future Work ## Practical Rule For Future Work
If something improves quality but creates visible hitch, it is not done. Move it to bake/cache/background work, split finalization over frames, or prewarm it before the player can see it. If something improves quality but creates visible hitch, it is not done. Move it to bake/cache/background work, split finalization over frames, or prewarm it before the player can see it.
@@ -0,0 +1,120 @@
# M03-RND-FACADE-ENVIRONMENT-001 — Renderer environment snapshot boundary
<!-- OPENWC_CLAIM:M03-RND-FACADE-ENVIRONMENT-001:sindo-main-codex:2026-07-18 -->
## Ownership
- Target: M03
- Program: RND
- Owner/Agent ID: sindo-main-codex
- Branch: `work/sindo-main-codex/m03-facade-environment`
- Lease expires UTC: 2026-07-18
- Integrator: M03 milestone integrator
## Outcome
Add an immutable world-environment snapshot accepted by `WorldRenderFacade`,
delegate it to the existing DBC sky controller, and migrate deterministic render
checkpoint time setup away from direct sky-controller property mutation.
## Non-goals
- Change Light/Area/Skybox DBC selection, interpolation, fog, sun or shader rules.
- Add weather, indoor lighting, new clock semantics or build-12340 parity claims.
- Extract the sky service or move its Environment/Node/RID ownership.
- Change runtime scene defaults, cache formats, streaming behavior or target status.
## Paths
- Exclusive: `src/render/environment/world_environment_snapshot.gd`,
`src/tools/verify_world_environment_snapshot.gd`, this claim
- Shared/hotspots: `src/render/world_render_facade.gd`,
`src/scenes/sky/wow_sky_controller.gd`, both runtime streaming scenes,
`src/tools/capture_render_checkpoints.gd`,
`src/tools/verify_world_render_facade.gd`, `docs/modules/world-renderer.md`,
`docs/modules/README.md`, `RENDER.md`, `targets/03-renderer-facade.md`
- Generated/ignored: `.godot`, native DLL, generated resources, caches and
proprietary renderer corpus
## Contracts and data
- Public API: immutable `WorldEnvironmentSnapshot` and
`WorldRenderFacade.apply_environment_snapshot`
- Snapshot input: finite time-of-day hours normalized into one 24-hour day
- Adapter: explicit `world_environment_controller_path`; facade/controller retain
no ownership of caller snapshot
- Schema/cache/coordinate contracts and runtime defaults: unchanged
- Consumer: deterministic renderer checkpoint capture; future world-state adapter
## Dependencies
- Requires: integrated M03 facade/ground-query master `cb103e1`
- Blocks: completion of the facade environment checklist slice and later sky extraction
- External state: none for contract tests; visual comparison still needs proprietary corpus
## Verification
- Commands: dedicated cold snapshot contract, facade delegation/wiring regression,
capture source-boundary regression, renderer manifest/dry-run and repository gates
- Fixtures: normalization, non-finite rejection, missing/wrong controller,
exact snapshot delegation and existing runtime scene wiring
- Fidelity evidence: preserve existing fixed-time application and all DBC-derived
visual logic; seven checkpoint plans remain valid
- Performance budget: one immutable value allocation per environment update and
constant-time main-thread delegation
## Documentation deliverables
- Inline public API docs: snapshot, facade adapter and sky-controller application
- Module specification: update existing world-renderer specification
- Data-flow diagram: snapshot producer through facade into DBC sky controller
- Sequence/state/dependency diagrams: application/failure path and ownership notes
- Source map/status updates: world-renderer module, module registry if needed, `RENDER.md`
## Simplicity and naming
- Important names introduced: `WorldEnvironmentSnapshot`, `apply_environment_snapshot`
- Simplest considered solution: one immutable time snapshot over the existing sky implementation
- Rejected complexity/abstractions: generic weather graph, duplicated lighting DTO,
event bus, service container or alternate Environment owner
- Unavoidable complexity and justification: facade resolves a separate scene-owned
sky controller because the streamer does not own outdoor environment rendering
- Measured optimization evidence: not applicable; bounded constant-time adapter
## Status
- State: ready-for-review
- Done: immutable value, facade/controller adapter, checkpoint migration,
regressions and renderer module documentation
- Next: M03 integrator reviews and merges `2ee647a`
- Blocked by:
<!-- OPENWC_HANDOFF:READY:M03-RND-FACADE-ENVIRONMENT-001:2ee647a -->
<!-- OPENWC_INTEGRATION:ACCEPTED:M03-RND-FACADE-ENVIRONMENT-001:c69abd6 -->
## Handoff
- Commit: `2ee647a`
- Results: `WorldEnvironmentSnapshot` normalizes finite time into one day and
exposes non-finite failure explicitly. `WorldRenderFacade` delegates the
immutable value to the existing sky controller; checkpoint capture no longer
locates or mutates that controller directly.
- Verification: snapshot `contract=5`; facade `delegation=6 ground_contract=2
environment_contract=7 runtime_scenes=2 tools=3`; internal access `43/7/9/1`;
terrain, coordinate (`files=116 consumers=5`), manifest (`7/7`), shutdown,
scheduler (`20000` iterations), planner (`250` iterations), focus, editor parse,
dry-run capture, coordination, documentation and diff gates passed.
- Fidelity: applying a snapshot retains the previous three fixed-clock assignments
and leaves DBC profile/area/skybox lookup, interpolation, fog, sun, shader,
cache and streaming rules unchanged. Dry-run retained all seven plans and
reported dusk as `time=19.00`. No build-12340 parity claim is added.
- External/local inputs: ignored native DLL and generated ADT resource scripts
were copied from master for parse/dry-run only. Missing proprietary ADT/DBC/
character data produced expected degraded diagnostics.
- Remaining risks: the snapshot currently covers exact world time only; weather,
indoor state and asset-backed paired zone-transition evidence remain open.
- Documentation updated: inline value/facade/controller API plus world-renderer
API/input-output/data-flow/sequence/ownership/failure/capability/source-map and
`RENDER.md` implementation notes.
- Integration: accepted in master merge `c69abd6`; post-merge snapshot, facade,
internal-access, manifest, shutdown, scheduler, planner and focus gates passed.
+37 -10
View File
@@ -5,9 +5,9 @@
| Field | Value | | Field | Value |
|---|---| |---|---|
| Status | Partial | | 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` | | 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` |
| Owners | Renderer workstream / milestone integrator | | Owners | Renderer workstream / milestone integrator |
| Last verified | Worktree `work/sindo-main-codex/m03-render-budget-scheduler`, 2026-07-16 | | Last verified | Worktree `work/sindo-main-codex/m03-facade-environment`, 2026-07-16 |
| Profiles/capabilities | `Performance`, `Balanced`, `High`, `Custom`; Blizzlike fidelity incomplete | | Profiles/capabilities | `Performance`, `Balanced`, `High`, `Custom`; Blizzlike fidelity incomplete |
## Purpose ## Purpose
@@ -44,7 +44,10 @@ flowchart LR
Parsed --> Loader Parsed --> Loader
Loader --> Scene[SceneTree nodes] Loader --> Scene[SceneTree nodes]
Loader --> RS[RenderingServer RIDs/MultiMesh] Loader --> RS[RenderingServer RIDs/MultiMesh]
Sky[DBC sky/light data] --> SkyController[WowSkyController] EnvironmentState[World time producer] --> EnvironmentSnapshot[WorldEnvironmentSnapshot]
EnvironmentSnapshot --> Facade
Facade --> SkyController[WowSkyController]
Sky[DBC sky/light data] --> SkyController
SkyController --> Scene SkyController --> Scene
``` ```
@@ -65,9 +68,10 @@ Forbidden dependencies:
## Public API ## Public API
Runtime, capture and probe callers use `WorldRenderFacade` for focus, metrics and Runtime, capture and probe callers use `WorldRenderFacade` for focus, immutable
rendered-ground diagnostics. `StreamingWorldLoader` remains the internal scene environment input, metrics and rendered-ground diagnostics. `StreamingWorldLoader`
implementation while later M03 packages add environment and entity-visual contracts. and `WowSkyController` remain internal scene implementations while a later M03
package adds entity-visual commands.
Gameplay modules and Godot `EditorPlugin` package sources are repository-gated Gameplay modules and Godot `EditorPlugin` package sources are repository-gated
from externally reading/writing loader-private queue, task, cache and tile-state fields. from externally reading/writing loader-private queue, task, cache and tile-state fields.
@@ -82,7 +86,10 @@ from externally reading/writing loader-private queue, task, cache and tile-state
| `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.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.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 | | `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.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 |
| `camera_path` | Exported property | Camera used only by optional automatic overview positioning | Main thread, scene lifetime | Missing camera skips automatic positioning | | `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 | | `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 | | `runtime_stats_enabled` | Exported property | Enables periodic performance snapshot | Runtime mutable | Logging overhead only |
@@ -99,6 +106,7 @@ loader configuration remains transitional composition data, not a caller API.
| Input | `StreamingFocus` | Player/spectator/editor/capture adapter | `WorldRenderFacade` | Immutable caller value | Main thread/session | | 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 | 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 | 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 | Map/configuration | Scene/app/editor | `StreamingWorldLoader` | Caller config, copied/read | Main thread/session | | 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 | 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 | | Input | Baked resources | Cache build tools | Streamer/builders | Shared immutable resource/cache entry | Session/cache lifetime |
@@ -147,6 +155,11 @@ flowchart TD
B --> Liquid[Liquid attach] B --> Liquid[Liquid attach]
Loaded[Loaded terrain Mesh and Transform] --> Ground[Facade ground query] Loaded[Loaded terrain Mesh and Transform] --> Ground[Facade ground query]
Ground --> GroundSample[RenderedGroundSample / detached diagnostics] Ground --> GroundSample[RenderedGroundSample / detached diagnostics]
WorldTime[Authoritative/test time] --> EnvironmentSnapshot[WorldEnvironmentSnapshot]
EnvironmentSnapshot --> RF
RF --> SkyController[WowSkyController]
DBC[Light/Area/Skybox DBC] --> SkyController
SkyController --> World
Terrain --> World[Godot world] Terrain --> World[Godot world]
M2 --> World M2 --> World
WMO --> World WMO --> World
@@ -202,6 +215,9 @@ sequenceDiagram
Source->>Facade: sample_ground_height(typed position) Source->>Facade: sample_ground_height(typed position)
Facade->>Stream: sample loaded render terrain Facade->>Stream: sample loaded render terrain
Stream-->>Facade: RenderedGroundSample / diagnostic snapshot 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
Stream->>Budget: shutdown: cancel permit issuance Stream->>Budget: shutdown: cancel permit issuance
Stream->>Worker: shutdown: wait for WorkerThreadPool tasks Stream->>Worker: shutdown: wait for WorkerThreadPool tasks
Stream->>Stream: shutdown: finish registered ResourceLoader requests Stream->>Stream: shutdown: finish registered ResourceLoader requests
@@ -213,7 +229,13 @@ sequenceDiagram
- `StreamingWorldLoader` владеет tile states, queues, task registries, active world instances и render caches session scope. - `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 - `WorldRenderFacade` owns only scene-relative adapter paths. It does not own the
streamer, focus source, returned metrics, queues, caches, nodes or RIDs. 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.
- Rendered-ground query results and diagnostic snapshots are caller-owned values; - Rendered-ground query results and diagnostic snapshots are caller-owned values;
the facade never returns Mesh, Node, tile-state or queue references. the facade never returns Mesh, Node, tile-state or queue references.
- Loaded-mesh ground sampling is renderer diagnostics, not authoritative gameplay - Loaded-mesh ground sampling is renderer diagnostics, not authoritative gameplay
@@ -240,6 +262,8 @@ sequenceDiagram
| 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 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 | | 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 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 |
| No focus supplied | Refresh contract | No target recomputation; queues continue draining | `refresh_streaming_focus()` returns `false` | Supply player/editor/capture focus | | 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 | | 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 | | Worker failure | Task result/empty data | Skip/degrade affected asset | Queue/task warning | Retry/rebuild source |
@@ -320,7 +344,8 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
| Character presentation | Prototype | Character creator/player experiment | Full customization/equipment states | | 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 | | 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 | | 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 | Partial | Facade contracts cover focus, metrics and loaded-mesh ground query | Environment and entity visuals remain | | Stable renderer facade | Partial | Facade contracts cover focus, environment time, metrics and loaded-mesh ground query | Entity visuals 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 |
| 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 | | 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 | | 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 | | 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 |
@@ -353,7 +378,8 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
| Path | Responsibility | | Path | Responsibility |
|---|---| |---|---|
| `src/render/world_render_facade.gd` | Stable caller boundary for typed focus, detached metrics and rendered-ground queries | | `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/terrain/rendered_ground_sample.gd` | Immutable renderer-owned available/unavailable ground query result | | `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_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_policy.gd` | Immutable renderer radius/prefetch policy |
@@ -362,7 +388,8 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
| `src/scenes/streaming/streaming_world_loader.gd` | Current runtime orchestration, queues, caches and attachment | | `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/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_streaming_focus.gd` | Headless contract, dependency and runtime/tool wiring regression |
| `src/tools/verify_world_render_facade.gd` | Focus/metrics/ground delegation, snapshot isolation and consumer 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_rendered_ground_sample.gd` | Cold-start renderer ground result invariant 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_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_render_budget_scheduler.gd` | Scheduler bounds, shared-lane priority, cancellation and timing regression |
@@ -0,0 +1,40 @@
class_name WorldEnvironmentSnapshot
extends RefCounted
## Immutable renderer input describing the authoritative time within one world day.
## DBC light, area, fog and skybox selection remain owned by the sky controller.
const HOURS_PER_DAY := 24.0
const SCRIPT_PATH := "res://src/render/environment/world_environment_snapshot.gd"
var is_valid: bool:
get:
return _is_valid
var time_of_day_hours: float:
get:
return _time_of_day_hours
var failure_code: StringName:
get:
return _failure_code
var _is_valid: bool
var _time_of_day_hours: float
var _failure_code: StringName
## Creates a snapshot and normalizes finite input into the half-open [0, 24) day.
## Non-finite input produces an explicit invalid value instead of renderer state.
static func at_time_of_day(time_of_day_hours_value: float) -> RefCounted:
return load(SCRIPT_PATH).new(time_of_day_hours_value)
func _init(time_of_day_hours_value: float) -> void:
_is_valid = is_finite(time_of_day_hours_value)
_time_of_day_hours = (
fposmod(time_of_day_hours_value, HOURS_PER_DAY)
if _is_valid
else 0.0
)
_failure_code = &"" if _is_valid else &"environment_time_not_finite"
@@ -0,0 +1 @@
uid://dass4mi3ex2fu
+39
View File
@@ -8,17 +8,24 @@ extends Node
const GODOT_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/godot_world_position.gd") const GODOT_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/godot_world_position.gd")
const STREAMING_FOCUS_SCRIPT := preload("res://src/domain/streaming/streaming_focus.gd") const STREAMING_FOCUS_SCRIPT := preload("res://src/domain/streaming/streaming_focus.gd")
const RENDERED_GROUND_SAMPLE_SCRIPT := preload("res://src/render/terrain/rendered_ground_sample.gd") const RENDERED_GROUND_SAMPLE_SCRIPT := preload("res://src/render/terrain/rendered_ground_sample.gd")
const WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT := preload("res://src/render/environment/world_environment_snapshot.gd")
## Internal renderer implementation resolved relative to this node. ## Internal renderer implementation resolved relative to this node.
## The referenced node remains owned by its scene parent. ## The referenced node remains owned by its scene parent.
@export var streaming_world_loader_path: NodePath = NodePath("..") @export var streaming_world_loader_path: NodePath = NodePath("..")
## Scene-owned outdoor environment implementation resolved relative to this node.
## The facade delegates snapshots but owns neither the controller nor Environment.
@export var world_environment_controller_path: NodePath = NodePath("../WowSkyController")
## Optional explicit Node3D source sampled in Godot world coordinates. ## Optional explicit Node3D source sampled in Godot world coordinates.
## Runtime scenes use the player; capture and probe tools replace it with their camera. ## Runtime scenes use the player; capture and probe tools replace it with their camera.
@export var streaming_focus_source_path: NodePath @export var streaming_focus_source_path: NodePath
var _streaming_world_loader: Node var _streaming_world_loader: Node
var _world_environment_controller: Node
var _missing_loader_reported := false var _missing_loader_reported := false
var _missing_environment_controller_reported := false
var _missing_focus_source_reported := false var _missing_focus_source_reported := false
@@ -94,6 +101,21 @@ func renderer_ground_query_snapshot(godot_world_position: GodotWorldPosition) ->
return (snapshot_variant as Dictionary).duplicate(true) return (snapshot_variant as Dictionary).duplicate(true)
## Applies an immutable environment snapshot through the renderer-owned sky path.
## Returns false for an invalid value or unavailable/incompatible controller.
func apply_environment_snapshot(world_environment_snapshot: RefCounted) -> bool:
if (
world_environment_snapshot == null
or world_environment_snapshot.get_script() != WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT
or not bool(world_environment_snapshot.get("is_valid"))
):
return false
var controller := _resolve_world_environment_controller()
if controller == null:
return false
return bool(controller.call("apply_environment_snapshot", world_environment_snapshot))
func _capture_streaming_focus_from_source() -> void: func _capture_streaming_focus_from_source() -> void:
if streaming_focus_source_path == NodePath(): if streaming_focus_source_path == NodePath():
return return
@@ -138,3 +160,20 @@ func _resolve_streaming_world_loader() -> Node:
_streaming_world_loader = candidate _streaming_world_loader = candidate
_missing_loader_reported = false _missing_loader_reported = false
return _streaming_world_loader return _streaming_world_loader
func _resolve_world_environment_controller() -> Node:
if is_instance_valid(_world_environment_controller):
return _world_environment_controller
var candidate := get_node_or_null(world_environment_controller_path)
if candidate == null or not candidate.has_method(&"apply_environment_snapshot"):
if not _missing_environment_controller_reported:
push_error(
"WorldRenderFacade cannot resolve a compatible environment controller at %s"
% world_environment_controller_path
)
_missing_environment_controller_reported = true
return null
_world_environment_controller = candidate
_missing_environment_controller_reported = false
return _world_environment_controller
+17
View File
@@ -4,6 +4,7 @@ extends Node
const M2_BUILDER_SCRIPT := preload("res://addons/mpq_extractor/loaders/m2_builder.gd") const M2_BUILDER_SCRIPT := preload("res://addons/mpq_extractor/loaders/m2_builder.gd")
const COORDINATE_MAPPER_SCRIPT := preload("res://src/domain/coordinates/coordinate_mapper.gd") const COORDINATE_MAPPER_SCRIPT := preload("res://src/domain/coordinates/coordinate_mapper.gd")
const GODOT_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/godot_world_position.gd") const GODOT_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/godot_world_position.gd")
const WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT := preload("res://src/render/environment/world_environment_snapshot.gd")
const LIGHT_COORD_SCALE := 36.0 const LIGHT_COORD_SCALE := 36.0
const HALF_MINUTES_PER_DAY := 2880 const HALF_MINUTES_PER_DAY := 2880
@@ -133,6 +134,22 @@ func _process(delta: float) -> void:
_update_skybox_transform() _update_skybox_transform()
## Accepts an authoritative time snapshot without moving DBC visual selection out
## of this controller. Existing fixed-clock behavior is preserved and frozen until
## another snapshot or explicit local clock configuration is supplied.
func apply_environment_snapshot(world_environment_snapshot: RefCounted) -> bool:
if (
world_environment_snapshot == null
or world_environment_snapshot.get_script() != WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT
or not bool(world_environment_snapshot.get("is_valid"))
):
return false
use_system_time = false
time_speed = 0.0
fixed_time_hours = float(world_environment_snapshot.get("time_of_day_hours"))
return true
func _resolve_nodes() -> void: func _resolve_nodes() -> void:
if not world_environment_path.is_empty(): if not world_environment_path.is_empty():
_world_environment = get_node_or_null(world_environment_path) as WorldEnvironment _world_environment = get_node_or_null(world_environment_path) as WorldEnvironment
@@ -98,6 +98,7 @@ hitch_profiler_enabled = true
script = ExtResource("7_render_facade") script = ExtResource("7_render_facade")
streaming_world_loader_path = NodePath("..") streaming_world_loader_path = NodePath("..")
streaming_focus_source_path = NodePath("../ThirdPersonPlayer") streaming_focus_source_path = NodePath("../ThirdPersonPlayer")
world_environment_controller_path = NodePath("../WowSkyController")
[node name="ThirdPersonPlayer" type="CharacterBody3D" parent="." unique_id=502573687] [node name="ThirdPersonPlayer" type="CharacterBody3D" parent="." unique_id=502573687]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 16800, 80, 26400) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 16800, 80, 26400)
@@ -99,6 +99,7 @@ hitch_profiler_enabled = true
script = ExtResource("7_render_facade") script = ExtResource("7_render_facade")
streaming_world_loader_path = NodePath("..") streaming_world_loader_path = NodePath("..")
streaming_focus_source_path = NodePath("../ThirdPersonPlayer") streaming_focus_source_path = NodePath("../ThirdPersonPlayer")
world_environment_controller_path = NodePath("../WowSkyController")
[node name="ThirdPersonPlayer" type="CharacterBody3D" parent="." unique_id=502573687] [node name="ThirdPersonPlayer" type="CharacterBody3D" parent="." unique_id=502573687]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 16800, 80, 26400) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 16800, 80, 26400)
+6 -7
View File
@@ -2,6 +2,7 @@ extends SceneTree
const DEFAULT_MANIFEST_PATH := "res://src/tools/render_baseline_manifest.json" const DEFAULT_MANIFEST_PATH := "res://src/tools/render_baseline_manifest.json"
const M2_NATIVE_ANIMATED_BUILDER := preload("res://addons/mpq_extractor/loaders/m2_native_animated_builder.gd") const M2_NATIVE_ANIMATED_BUILDER := preload("res://addons/mpq_extractor/loaders/m2_native_animated_builder.gd")
const WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT := preload("res://src/render/environment/world_environment_snapshot.gd")
const SHUTDOWN_DRAIN_FRAMES := 2 const SHUTDOWN_DRAIN_FRAMES := 2
@@ -130,7 +131,7 @@ func _capture_async() -> void:
camera.make_current() camera.make_current()
if player != null: if player != null:
player.global_position = _vector3(checkpoint.get("player", checkpoint.get("target", [0.0, 0.0, 0.0]))) player.global_position = _vector3(checkpoint.get("player", checkpoint.get("target", [0.0, 0.0, 0.0])))
_set_sky_time(world, float(checkpoint.get("time_hours", 13.0))) _apply_environment_time(render_facade, float(checkpoint.get("time_hours", 13.0)))
render_facade.call("refresh_streaming_focus", true) render_facade.call("refresh_streaming_focus", true)
if dry_run: if dry_run:
@@ -308,12 +309,10 @@ func _create_diagnostic_spawn_marker(checkpoint: Dictionary) -> Node3D:
return marker_root return marker_root
func _set_sky_time(world: Node, time_hours: float) -> void: func _apply_environment_time(render_facade: Node, time_hours: float) -> void:
var sky := world.get_node_or_null("WowSkyController") var environment_snapshot: RefCounted = WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT.at_time_of_day(time_hours)
if sky != null: if not bool(render_facade.call("apply_environment_snapshot", environment_snapshot)):
sky.set("use_system_time", false) push_error("Render checkpoint could not apply environment time %.3f" % time_hours)
sky.set("time_speed", 0.0)
sky.set("fixed_time_hours", time_hours)
func _environment_metadata() -> Dictionary: func _environment_metadata() -> Dictionary:
@@ -0,0 +1,43 @@
extends SceneTree
## Cold-start contract for immutable renderer environment input.
const SNAPSHOT_SCRIPT := preload("res://src/render/environment/world_environment_snapshot.gd")
func _initialize() -> void:
var failures: Array[String] = []
var afternoon: RefCounted = SNAPSHOT_SCRIPT.at_time_of_day(13.5)
_expect_true(bool(afternoon.get("is_valid")), "finite snapshot", failures)
_expect_near(float(afternoon.get("time_of_day_hours")), 13.5, "finite time", failures)
var wrapped: RefCounted = SNAPSHOT_SCRIPT.at_time_of_day(25.25)
_expect_near(float(wrapped.get("time_of_day_hours")), 1.25, "positive day wrap", failures)
var negative: RefCounted = SNAPSHOT_SCRIPT.at_time_of_day(-1.0)
_expect_near(float(negative.get("time_of_day_hours")), 23.0, "negative day wrap", failures)
var invalid: RefCounted = SNAPSHOT_SCRIPT.at_time_of_day(INF)
_expect_true(not bool(invalid.get("is_valid")), "non-finite invalid", failures)
_expect_true(
StringName(invalid.get("failure_code")) == &"environment_time_not_finite",
"non-finite failure code",
failures
)
if not failures.is_empty():
for failure in failures:
push_error("WORLD_ENVIRONMENT_SNAPSHOT: %s" % failure)
quit(1)
return
print("WORLD_ENVIRONMENT_SNAPSHOT PASS contract=5")
quit(0)
func _expect_near(actual_value: float, expected_value: float, label: String, failures: Array[String]) -> void:
if not is_equal_approx(actual_value, expected_value):
failures.append("%s expected %.3f, got %.3f" % [label, expected_value, actual_value])
func _expect_true(actual_value: bool, label: String, failures: Array[String]) -> void:
if not actual_value:
failures.append("%s expected true" % label)
@@ -0,0 +1 @@
uid://e85kt58s0ca4
+70 -1
View File
@@ -6,6 +6,8 @@ const WORLD_RENDER_FACADE_SCRIPT := preload("res://src/render/world_render_facad
const GODOT_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/godot_world_position.gd") const GODOT_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/godot_world_position.gd")
const STREAMING_FOCUS_SCRIPT := preload("res://src/domain/streaming/streaming_focus.gd") const STREAMING_FOCUS_SCRIPT := preload("res://src/domain/streaming/streaming_focus.gd")
const RENDERED_GROUND_SAMPLE_SCRIPT := preload("res://src/render/terrain/rendered_ground_sample.gd") const RENDERED_GROUND_SAMPLE_SCRIPT := preload("res://src/render/terrain/rendered_ground_sample.gd")
const WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT := preload("res://src/render/environment/world_environment_snapshot.gd")
const WOW_SKY_CONTROLLER_SCRIPT := preload("res://src/scenes/sky/wow_sky_controller.gd")
const RUNTIME_SCENE_PATHS: Array[String] = [ const RUNTIME_SCENE_PATHS: Array[String] = [
"res://src/scenes/streaming/eastern_kingdoms_streaming.tscn", "res://src/scenes/streaming/eastern_kingdoms_streaming.tscn",
@@ -47,9 +49,18 @@ class StreamingWorldLoaderDouble extends Node:
return ground_snapshot return ground_snapshot
class WorldEnvironmentControllerDouble extends Node:
var applied_snapshot: RefCounted
func apply_environment_snapshot(world_environment_snapshot: RefCounted) -> bool:
applied_snapshot = world_environment_snapshot
return true
func _initialize() -> void: func _initialize() -> void:
var failures: Array[String] = [] var failures: Array[String] = []
_verify_rendered_ground_sample_contract(failures) _verify_rendered_ground_sample_contract(failures)
_verify_sky_controller_application(failures)
await _verify_delegation_and_snapshot_isolation(failures) await _verify_delegation_and_snapshot_isolation(failures)
_verify_repository_wiring(failures) _verify_repository_wiring(failures)
@@ -59,7 +70,7 @@ func _initialize() -> void:
quit(1) quit(1)
return return
print("WORLD_RENDER_FACADE PASS delegation=5 ground_contract=2 runtime_scenes=2 tools=3") print("WORLD_RENDER_FACADE PASS delegation=6 ground_contract=2 environment_contract=7 runtime_scenes=2 tools=3")
quit(0) quit(0)
@@ -79,6 +90,23 @@ func _verify_rendered_ground_sample_contract(failures: Array[String]) -> void:
) )
func _verify_sky_controller_application(failures: Array[String]) -> void:
var controller: Node = WOW_SKY_CONTROLLER_SCRIPT.new()
controller.set("use_system_time", true)
controller.set("time_speed", 4.0)
controller.set("fixed_time_hours", 3.0)
var snapshot: RefCounted = WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT.at_time_of_day(18.75)
_expect_true(
bool(controller.call("apply_environment_snapshot", snapshot)),
"sky controller accepts snapshot",
failures
)
_expect_true(not bool(controller.get("use_system_time")), "snapshot disables system clock", failures)
_expect_near(float(controller.get("time_speed")), 0.0, "snapshot freezes local clock", failures)
_expect_near(float(controller.get("fixed_time_hours")), 18.75, "snapshot applies exact time", failures)
controller.free()
func _verify_delegation_and_snapshot_isolation(failures: Array[String]) -> void: func _verify_delegation_and_snapshot_isolation(failures: Array[String]) -> void:
var test_root := Node.new() var test_root := Node.new()
var loader := StreamingWorldLoaderDouble.new() var loader := StreamingWorldLoaderDouble.new()
@@ -86,12 +114,16 @@ func _verify_delegation_and_snapshot_isolation(failures: Array[String]) -> void:
var source := Node3D.new() var source := Node3D.new()
source.name = "FocusSource" source.name = "FocusSource"
source.position = Vector3(10.0, 20.0, 30.0) source.position = Vector3(10.0, 20.0, 30.0)
var environment_controller := WorldEnvironmentControllerDouble.new()
environment_controller.name = "WorldEnvironmentControllerDouble"
var facade = WORLD_RENDER_FACADE_SCRIPT.new() var facade = WORLD_RENDER_FACADE_SCRIPT.new()
facade.name = "WorldRenderFacade" facade.name = "WorldRenderFacade"
facade.streaming_world_loader_path = NodePath("../StreamingWorldLoaderDouble") facade.streaming_world_loader_path = NodePath("../StreamingWorldLoaderDouble")
facade.streaming_focus_source_path = NodePath("../FocusSource") facade.streaming_focus_source_path = NodePath("../FocusSource")
facade.world_environment_controller_path = NodePath("../WorldEnvironmentControllerDouble")
test_root.add_child(loader) test_root.add_child(loader)
test_root.add_child(source) test_root.add_child(source)
test_root.add_child(environment_controller)
test_root.add_child(facade) test_root.add_child(facade)
get_root().add_child(test_root) get_root().add_child(test_root)
await process_frame await process_frame
@@ -131,6 +163,24 @@ func _verify_delegation_and_snapshot_isolation(failures: Array[String]) -> void:
(ground_snapshot["diagnostic"] as Dictionary)["state_present"] = false (ground_snapshot["diagnostic"] as Dictionary)["state_present"] = false
_expect_near(float(loader.ground_snapshot.terrain_height), 42.25, "ground snapshot top-level detached", failures) _expect_near(float(loader.ground_snapshot.terrain_height), 42.25, "ground snapshot top-level detached", failures)
_expect_true(bool(loader.ground_snapshot.diagnostic.state_present), "ground snapshot nested detached", failures) _expect_true(bool(loader.ground_snapshot.diagnostic.state_present), "ground snapshot nested detached", failures)
var environment_snapshot: RefCounted = WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT.at_time_of_day(18.75)
_expect_true(
facade.apply_environment_snapshot(environment_snapshot),
"environment snapshot delegates",
failures
)
_expect_true(
environment_controller.applied_snapshot == environment_snapshot,
"environment snapshot reference delegates",
failures
)
var invalid_environment_snapshot: RefCounted = WORLD_ENVIRONMENT_SNAPSHOT_SCRIPT.at_time_of_day(NAN)
_expect_true(
not facade.apply_environment_snapshot(invalid_environment_snapshot),
"invalid environment snapshot rejected",
failures
)
test_root.queue_free() test_root.queue_free()
@@ -140,6 +190,7 @@ func _verify_repository_wiring(failures: Array[String]) -> void:
_expect_true(scene_source.contains('path="res://src/render/world_render_facade.gd"'), "%s loads facade" % scene_path, failures) _expect_true(scene_source.contains('path="res://src/render/world_render_facade.gd"'), "%s loads facade" % scene_path, failures)
_expect_true(scene_source.contains('[node name="WorldRenderFacade" type="Node" parent="."]'), "%s owns facade node" % scene_path, failures) _expect_true(scene_source.contains('[node name="WorldRenderFacade" type="Node" parent="."]'), "%s owns facade node" % scene_path, failures)
_expect_true(scene_source.contains('streaming_focus_source_path = NodePath("../ThirdPersonPlayer")'), "%s facade uses player focus" % scene_path, failures) _expect_true(scene_source.contains('streaming_focus_source_path = NodePath("../ThirdPersonPlayer")'), "%s facade uses player focus" % scene_path, failures)
_expect_true(scene_source.contains('world_environment_controller_path = NodePath("../WowSkyController")'), "%s facade uses sky controller" % scene_path, failures)
for tool_path in TOOL_PATHS: for tool_path in TOOL_PATHS:
var tool_source := _read_text(tool_path, failures) var tool_source := _read_text(tool_path, failures)
@@ -171,6 +222,24 @@ func _verify_repository_wiring(failures: Array[String]) -> void:
failures failures
) )
var capture_source := _read_text("res://src/tools/capture_render_checkpoints.gd", failures)
_expect_true(
capture_source.contains('call("apply_environment_snapshot", environment_snapshot)'),
"capture applies environment through facade",
failures
)
for forbidden_capture_text in [
'get_node_or_null("WowSkyController")',
'sky.set("use_system_time"',
'sky.set("time_speed"',
'sky.set("fixed_time_hours"',
]:
_expect_true(
not capture_source.contains(forbidden_capture_text),
"capture omits direct sky mutation %s" % forbidden_capture_text,
failures
)
var loader_source := _read_text(STREAMING_WORLD_LOADER_PATH, failures) var loader_source := _read_text(STREAMING_WORLD_LOADER_PATH, failures)
for required_loader_text in [ for required_loader_text in [
"func sample_rendered_ground_height(godot_world_position: GodotWorldPosition)", "func sample_rendered_ground_height(godot_world_position: GodotWorldPosition)",
+12 -5
View File
@@ -27,9 +27,9 @@ Runtime и Editor используют facade; planner/scheduler тестиру
## Evidence ## Evidence
- Date: 2026-07-16 - Date: 2026-07-16
- Revision/worktree: master merges `7ece2ab`, `7e35de7`, `80cb084`, `d6e5b53`; - Revision/worktree: master merges `7ece2ab`, `7e35de7`, `80cb084`, `d6e5b53`, `c69abd6`;
packages `M03-RND-SCHEDULER-001`, `M03-RND-INTERNAL-ACCESS-GATE-001`, packages `M03-RND-SCHEDULER-001`, `M03-RND-INTERNAL-ACCESS-GATE-001`,
`M03-RND-FACADE-GROUND-QUERY-001` `M03-RND-FACADE-GROUND-QUERY-001`, `M03-RND-FACADE-ENVIRONMENT-001`
- Commands: dedicated scheduler/planner/facade/focus/coordinate/manifest/shutdown - Commands: dedicated scheduler/planner/facade/focus/coordinate/manifest/shutdown
headless verifiers; Godot cold editor parse; coordination, documentation and diff gates. headless verifiers; Godot cold editor parse; coordination, documentation and diff gates.
- Results: scheduler `cases=6 iterations=20000 elapsed_ms=10.216`; planner - Results: scheduler `cases=6 iterations=20000 elapsed_ms=10.216`; planner
@@ -39,18 +39,25 @@ Runtime и Editor используют facade; planner/scheduler тестиру
derived `43` private symbols and found no forbidden access across `7` gameplay derived `43` private symbols and found no forbidden access across `7` gameplay
and `9` EditorPlugin-package sources plus the terrain probe. Ground facade passed and `9` EditorPlugin-package sources plus the terrain probe. Ground facade passed
`delegation=5 ground_contract=2`; cold `RenderedGroundSample contract=3`; `delegation=5 ground_contract=2`; cold `RenderedGroundSample contract=3`;
M02 terrain-query regression remained green (13 pre-existing expired M00 claim warnings). environment integration passed cold snapshot `contract=5` and facade
`delegation=6 environment_contract=7`; dry-run retained all `7/7` plans and
applied the dusk checkpoint at `time=19.00`. M02 terrain-query regression
remained green (13 pre-existing expired M00 claim warnings).
- Fidelity comparison: all 16 historical operation limits and drain sites were - Fidelity comparison: all 16 historical operation limits and drain sites were
preserved; chunk removal/create retain their shared removal-first budget. preserved; chunk removal/create retain their shared removal-first budget.
Defaults, quality presets, cache versions and visual rules are unchanged. Defaults, quality presets, cache versions and visual rules are unchanged.
Rendered-ground diagnostics preserve the prior 5000-unit ray, 3x3 search and Rendered-ground diagnostics preserve the prior 5000-unit ray, 3x3 search and
`2/5/10/20/40`-unit nearby fallback while hiding mutable renderer state. `2/5/10/20/40`-unit nearby fallback while hiding mutable renderer state.
Environment snapshots preserve the prior fixed-clock assignments while DBC
profile/area/skybox selection, interpolation, fog, sun and shader rules remain unchanged.
No new build-12340 parity claim is made; asset-backed visual/p95/p99 comparison remains pending. No new build-12340 parity claim is made; asset-backed visual/p95/p99 comparison remains pending.
- Changed files: scene-free scheduler and verifier; streamer budget composition/ - Changed files: scene-free scheduler and verifier; streamer budget composition/
permit delegation; scheduler module spec; world renderer/module registry/RENDER notes; permit delegation; scheduler module spec; world renderer/module registry/RENDER notes;
renderer-owned ground sample, facade/loader ground query, migrated terrain probe, renderer-owned ground sample, facade/loader ground query, migrated terrain probe,
expanded internal-access/coordinate verifiers; work-package claims and this evidence. immutable environment snapshot, facade/sky adapter, migrated checkpoint time input,
expanded facade/internal-access/coordinate verifiers; work-package claims and this evidence.
- Remaining risks: queue storage length and worker concurrency/stale-result logic - Remaining risks: queue storage length and worker concurrency/stale-result logic
remain streamer-owned; cancellation stops new permits but does not interrupt remain streamer-owned; cancellation stops new permits but does not interrupt
in-flight work; M03 still needs environment/entity facade contracts, service extraction in-flight work; the environment snapshot currently covers world time but not weather
or indoor state; M03 still needs entity facade commands, service extraction
and dependency/performance acceptance. and dependency/performance acceptance.