Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90b1dac56e | |||
| 874fd0f3f2 | |||
| 9cb8bdb137 | |||
| 235be3a36c | |||
| 4f8fc3b3b8 |
@@ -34,6 +34,7 @@ Paired run 2026-07-11 подтвердил крупный coordinate/placement g
|
|||||||
- `src/render/wmo/wmo_render_resource_cache_state.gd` - validated lightweight WMO render Resources, negative cache and pending cache paths without ResourceLoader I/O.
|
- `src/render/wmo/wmo_render_resource_cache_state.gd` - validated lightweight WMO render Resources, negative cache and pending cache paths without ResourceLoader I/O.
|
||||||
- `src/render/wmo/wmo_scene_resource_cache_state.gd` - validated cached-WMO PackedScenes, negative cache and pending `.tscn` paths without file/I/O/Node ownership.
|
- `src/render/wmo/wmo_scene_resource_cache_state.gd` - validated cached-WMO PackedScenes, negative cache and pending `.tscn` paths without file/I/O/Node ownership.
|
||||||
- `src/render/liquid/adt_water_load_pipeline_state.gd` - ADT water pending FIFO/dedupe, active task IDs and worker-safe parsed-result mailbox without parser or Node ownership.
|
- `src/render/liquid/adt_water_load_pipeline_state.gd` - ADT water pending FIFO/dedupe, active task IDs and worker-safe parsed-result mailbox without parser or Node ownership.
|
||||||
|
- `src/render/liquid/adt_water_scene_finalizer.gd` - stateless main-thread ADT water build/attach and optional persisted Editor ownership through the existing ADTBuilder.
|
||||||
- `src/scenes/streaming/eastern_kingdoms_streaming.tscn` - текущая сцена для проверки Azeroth/Eastern Kingdoms.
|
- `src/scenes/streaming/eastern_kingdoms_streaming.tscn` - текущая сцена для проверки Azeroth/Eastern Kingdoms.
|
||||||
- `addons/mpq_extractor/loaders/adt_builder.gd` - сборка ADT terrain, control splat материалов и MH2O liquids.
|
- `addons/mpq_extractor/loaders/adt_builder.gd` - сборка ADT terrain, control splat материалов и MH2O liquids.
|
||||||
- `addons/mpq_extractor/loaders/m2_builder.gd` - сборка статического M2 mesh/material.
|
- `addons/mpq_extractor/loaders/m2_builder.gd` - сборка статического M2 mesh/material.
|
||||||
@@ -1084,7 +1085,8 @@ $exe = Join-Path $env:TEMP 'godot-4.6.1-openwc\Godot_v4.6.1-stable_win64.exe'
|
|||||||
active WorkerThreadPool task IDs and the mutex-protected parsed-result mailbox.
|
active WorkerThreadPool task IDs and the mutex-protected parsed-result mailbox.
|
||||||
- `StreamingWorldLoader` still selects concurrency, starts/waits tasks, invokes
|
- `StreamingWorldLoader` still selects concurrency, starts/waits tasks, invokes
|
||||||
`ADTLoader`, consumes `WATER_FINALIZE` permits, rejects stale tile/path/root
|
`ADTLoader`, consumes `WATER_FINALIZE` permits, rejects stale tile/path/root
|
||||||
results and builds/attaches water Nodes through `ADTBuilder` on the main thread.
|
results and owns `water_loaded` timing. Main-thread Water subtree construction
|
||||||
|
and attachment are delegated separately as described below.
|
||||||
- Tile release still cancels only pending water requests; active work completes
|
- Tile release still cancels only pending water requests; active work completes
|
||||||
and its result is discarded when tile ownership is stale. Shutdown waits task
|
and its result is discarded when tile ownership is stale. Shutdown waits task
|
||||||
IDs before clearing state; reset does not interrupt workers.
|
IDs before clearing state; reset does not interrupt workers.
|
||||||
@@ -1093,6 +1095,23 @@ $exe = Join-Path $env:TEMP 'godot-4.6.1-openwc\Godot_v4.6.1-stable_win64.exe'
|
|||||||
- Asset-backed MH2O/MCLQ fidelity, long-traversal leak/p95/p99 and paired capture
|
- Asset-backed MH2O/MCLQ fidelity, long-traversal leak/p95/p99 and paired capture
|
||||||
evidence remain pending.
|
evidence remain pending.
|
||||||
|
|
||||||
|
## 2026-07-17 ADT Water Scene Finalizer Extraction
|
||||||
|
|
||||||
|
- `AdtWaterSceneFinalizer` now owns the two main-thread operations that turn
|
||||||
|
validated parsed ADT data into a Water subtree: the existing
|
||||||
|
`ADTBuilder.build_tile_water_scene` call and attachment to the tile root.
|
||||||
|
- Both raw tile finalization and delayed cached-tile water results use the same
|
||||||
|
service. Optional persisted Editor ownership is assigned recursively only
|
||||||
|
when the loader supplies its existing edited-scene owner.
|
||||||
|
- The service is stateless and retains no Node, Mesh, material or RID. The tile
|
||||||
|
SceneTree subtree remains the lifetime owner; dry data still causes ADTBuilder
|
||||||
|
to free its temporary empty Water root.
|
||||||
|
- Parsing, task/result state, concurrency, stale validation, `WATER_FINALIZE`
|
||||||
|
permits, `enable_water` and `water_loaded` timing remain loader-owned.
|
||||||
|
- Geometry, materials, coordinates, cache formats, profiles and visible output
|
||||||
|
are unchanged. Synthetic geometry/ownership evidence is not an MH2O/MCLQ or
|
||||||
|
original-client parity claim; asset-backed traversal/p95/p99 remains pending.
|
||||||
|
|
||||||
## 2026-07-16 World Environment Snapshot Facade
|
## 2026-07-16 World Environment Snapshot Facade
|
||||||
|
|
||||||
- `WorldEnvironmentSnapshot` carries one immutable finite time-of-day value,
|
- `WorldEnvironmentSnapshot` carries one immutable finite time-of-day value,
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# M03-RND-ADT-WATER-SCENE-FINALIZER-001 — ADT water scene finalizer
|
||||||
|
|
||||||
|
<!-- OPENWC_CLAIM:M03-RND-ADT-WATER-SCENE-FINALIZER-001:sindo-main-codex:2026-07-20 -->
|
||||||
|
|
||||||
|
## Ownership
|
||||||
|
|
||||||
|
- Target: M03
|
||||||
|
- Program: RND
|
||||||
|
- Owner/Agent ID: sindo-main-codex
|
||||||
|
- Branch: `work/sindo-main-codex/m03-adt-water-scene-finalizer`
|
||||||
|
- Lease expires UTC: 2026-07-20
|
||||||
|
- Integrator: M03 milestone integrator
|
||||||
|
|
||||||
|
## Outcome
|
||||||
|
|
||||||
|
Extract main-thread ADT water subtree construction, tile-root attachment and
|
||||||
|
optional recursive editor ownership from `StreamingWorldLoader` while retaining
|
||||||
|
the existing `ADTBuilder` geometry/material implementation.
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- Parse or reinterpret MH2O/MCLQ data.
|
||||||
|
- Own pending requests, WorkerThreadPool tasks or parsed-result delivery.
|
||||||
|
- Consume `WATER_FINALIZE` permits or validate tile/path/result staleness.
|
||||||
|
- Mark tile state `water_loaded` or choose whether water is enabled.
|
||||||
|
- Change liquid geometry, materials, coordinates, cache formats or profiles.
|
||||||
|
|
||||||
|
## Paths
|
||||||
|
|
||||||
|
- Exclusive: `src/render/liquid/adt_water_scene_finalizer.gd`,
|
||||||
|
`src/tools/verify_adt_water_scene_finalizer.gd`,
|
||||||
|
`docs/modules/adt-water-scene-finalizer.md`, this claim
|
||||||
|
- Shared/hotspots: `src/scenes/streaming/streaming_world_loader.gd`,
|
||||||
|
`src/tools/verify_adt_water_load_pipeline_state.gd`,
|
||||||
|
`docs/modules/adt-water-load-pipeline-state.md`,
|
||||||
|
`docs/modules/world-renderer.md`, `docs/modules/README.md`, `RENDER.md`,
|
||||||
|
`targets/03-renderer-facade.md`
|
||||||
|
- Generated/ignored: `.godot`, native DLL, generated ADT resources, caches and
|
||||||
|
proprietary renderer corpus
|
||||||
|
|
||||||
|
## Contracts and data
|
||||||
|
|
||||||
|
- Empty water data or invalid tile root produces no Node and no scene mutation.
|
||||||
|
- Existing `ADTBuilder.build_tile_water_scene` remains the only geometry/material source.
|
||||||
|
- A non-empty built Water root is attached exactly once to the supplied tile root.
|
||||||
|
- Optional editor ownership is assigned recursively only when explicitly enabled
|
||||||
|
and an edited scene root is available.
|
||||||
|
- The returned Node is borrowed and remains owned by the tile SceneTree subtree.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- Requires: accepted water pipeline package on current master `e1b2886`
|
||||||
|
- Blocks: further liquid finalization/material responsibility extraction
|
||||||
|
- External state: none; verification uses synthetic liquid dictionaries
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- Commands: dedicated empty/invalid/build/attach/editor-owner/source/timing
|
||||||
|
verifier; water pipeline, materials, shutdown, facade, internal-access,
|
||||||
|
manifest, documentation and coordination gates
|
||||||
|
- Fixtures: synthetic one-cell liquid mask/heights and temporary Node roots
|
||||||
|
- Fidelity evidence: exact existing ADTBuilder output and two attachment paths preserved
|
||||||
|
- Performance budget: 100 empty finalization attempts under 1 second
|
||||||
|
|
||||||
|
## Documentation deliverables
|
||||||
|
|
||||||
|
- Inline public API docs
|
||||||
|
- Module specification with inputs/outputs, ownership and source map
|
||||||
|
- Data-flow, lifecycle/state, main-thread sequence and dependency diagrams
|
||||||
|
- Water-pipeline, world-renderer, module registry and RENDER status updates
|
||||||
|
|
||||||
|
## Simplicity and naming
|
||||||
|
|
||||||
|
- Important names introduced: `AdtWaterSceneFinalizer`
|
||||||
|
- Simplest considered solution: one RefCounted with one explicit attach operation
|
||||||
|
- Rejected complexity/abstractions: generic scene finalizer, signals, callbacks,
|
||||||
|
builder interface, queue ownership or alternate liquid renderer
|
||||||
|
- Unavoidable complexity and justification: editor-persisted generated subtrees
|
||||||
|
require recursive owner assignment after SceneTree attachment
|
||||||
|
- Measured optimization evidence: bounded synthetic no-water loop
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
- State: accepted
|
||||||
|
- Done: stateless finalizer implemented; both loader water paths migrated;
|
||||||
|
synthetic scene/owner regression and required documentation added
|
||||||
|
- Next: continue liquid parsing/task execution extraction or another remaining M03 boundary
|
||||||
|
- Blocked by:
|
||||||
|
|
||||||
|
<!-- OPENWC_INTEGRATION:ACCEPTED:M03-RND-ADT-WATER-SCENE-FINALIZER-001:874fd0f -->
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
- Commit: `235be3a`
|
||||||
|
- Results: scene finalizer PASS (`cases=8`, `iterations=100`,
|
||||||
|
`elapsed_ms=0.042`; initial `0.024ms`); synthetic liquid produced one
|
||||||
|
four-vertex/six-index surface with tile attachment and recursive owner; water
|
||||||
|
pipeline (`119.648ms`), WMO/M2/terrain/facade/scheduler/streaming/coordinate,
|
||||||
|
materials, shutdown, internal-access `36` and 32 headless contract regressions
|
||||||
|
PASS; documentation and coordination gates PASS; checkpoint dry-run PASS `7/7`.
|
||||||
|
- Remaining risks: main-thread mesh/material construction remains synchronous
|
||||||
|
behind one existing permit; the Dictionary builder boundary remains untyped;
|
||||||
|
proprietary MH2O/MCLQ traversal/leak/p95/p99/original-client evidence is absent.
|
||||||
|
A verifier launched concurrently with the initial cold editor import observed
|
||||||
|
the pre-existing global-class cache race; serialized editor parse and shutdown
|
||||||
|
rerun passed, with only expected missing private asset diagnostics.
|
||||||
|
- Documentation updated: inline public API; new
|
||||||
|
`docs/modules/adt-water-scene-finalizer.md`; water-pipeline spec, module registry,
|
||||||
|
world renderer and `RENDER.md`; data-flow/state/sequence/dependency diagrams,
|
||||||
|
ownership, main-thread effects, failure/recovery, migration and source map included.
|
||||||
|
- Integration: merged as `874fd0f`; post-merge finalizer (`cases=8`,
|
||||||
|
`iterations=100`, `elapsed_ms=0.025`), water pipeline (`98.398ms`), shutdown,
|
||||||
|
renderer materials, facade, internal-access (`private_symbols=36`), `7/7`
|
||||||
|
manifest, documentation and coordination gates passed.
|
||||||
|
|
||||||
|
<!-- OPENWC_HANDOFF:READY:M03-RND-ADT-WATER-SCENE-FINALIZER-001:235be3a -->
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
| Terrain chunk LOD planner | Implemented extraction | [`terrain-chunk-lod-planner.md`](terrain-chunk-lod-planner.md) |
|
| Terrain chunk LOD planner | Implemented extraction | [`terrain-chunk-lod-planner.md`](terrain-chunk-lod-planner.md) |
|
||||||
| Terrain chunk geometry queue planner | Implemented extraction | [`terrain-chunk-geometry-queue-planner.md`](terrain-chunk-geometry-queue-planner.md) |
|
| Terrain chunk geometry queue planner | Implemented extraction | [`terrain-chunk-geometry-queue-planner.md`](terrain-chunk-geometry-queue-planner.md) |
|
||||||
| ADT water load pipeline state | Implemented extraction | [`adt-water-load-pipeline-state.md`](adt-water-load-pipeline-state.md) |
|
| ADT water load pipeline state | Implemented extraction | [`adt-water-load-pipeline-state.md`](adt-water-load-pipeline-state.md) |
|
||||||
|
| ADT water scene finalizer | Implemented extraction | [`adt-water-scene-finalizer.md`](adt-water-scene-finalizer.md) |
|
||||||
| M2 unique placement registry | Implemented extraction | [`m2-unique-placement-registry.md`](m2-unique-placement-registry.md) |
|
| M2 unique placement registry | Implemented extraction | [`m2-unique-placement-registry.md`](m2-unique-placement-registry.md) |
|
||||||
| M2 placement transform resolver | Implemented | [`m2-placement-transform-resolver.md`](m2-placement-transform-resolver.md) |
|
| M2 placement transform resolver | Implemented | [`m2-placement-transform-resolver.md`](m2-placement-transform-resolver.md) |
|
||||||
| M2 placement grouper | Implemented extraction | [`m2-placement-grouper.md`](m2-placement-grouper.md) |
|
| M2 placement grouper | Implemented extraction | [`m2-placement-grouper.md`](m2-placement-grouper.md) |
|
||||||
|
|||||||
@@ -38,8 +38,9 @@ flowchart LR
|
|||||||
State --> Result[Parsed ADT result]
|
State --> Result[Parsed ADT result]
|
||||||
Result --> Loader
|
Result --> Loader
|
||||||
Loader --> Budget[WATER_FINALIZE permit]
|
Loader --> Budget[WATER_FINALIZE permit]
|
||||||
Loader --> Builder[ADTBuilder water scene]
|
Loader --> Finalizer[AdtWaterSceneFinalizer]
|
||||||
Builder --> Scene[Main-thread tile Node attach]
|
Finalizer --> Builder[ADTBuilder water scene]
|
||||||
|
Finalizer --> Scene[Main-thread tile Node attach]
|
||||||
```
|
```
|
||||||
|
|
||||||
Allowed dependencies are RefCounted, Dictionary/Array/String and one Godot
|
Allowed dependencies are RefCounted, Dictionary/Array/String and one Godot
|
||||||
@@ -127,7 +128,7 @@ sequenceDiagram
|
|||||||
participant State as AdtWaterLoadPipelineState
|
participant State as AdtWaterLoadPipelineState
|
||||||
participant Worker as WorkerThreadPool task
|
participant Worker as WorkerThreadPool task
|
||||||
participant Budget as RenderBudgetScheduler
|
participant Budget as RenderBudgetScheduler
|
||||||
participant Builder as ADTBuilder
|
participant Finalizer as AdtWaterSceneFinalizer
|
||||||
Loader->>State: enqueue_request(tile key, ADT path)
|
Loader->>State: enqueue_request(tile key, ADT path)
|
||||||
Loader->>State: take_next_request()
|
Loader->>State: take_next_request()
|
||||||
Loader->>Worker: add_task(parse binding)
|
Loader->>Worker: add_task(parse binding)
|
||||||
@@ -140,8 +141,8 @@ sequenceDiagram
|
|||||||
Loader->>Worker: wait_for_task_completion(task ID)
|
Loader->>Worker: wait_for_task_completion(task ID)
|
||||||
Loader->>State: complete_active_task(key)
|
Loader->>State: complete_active_task(key)
|
||||||
Loader->>Loader: reject stale tile/path/root
|
Loader->>Loader: reject stale tile/path/root
|
||||||
Loader->>Builder: build_tile_water_scene(data, origin)
|
Loader->>Finalizer: attach_water_scene(data, origin, tile root, editor owner)
|
||||||
Loader->>Loader: attach Node and mark water_loaded
|
Loader->>Loader: mark water_loaded
|
||||||
```
|
```
|
||||||
|
|
||||||
## Dependency diagram
|
## Dependency diagram
|
||||||
@@ -151,10 +152,11 @@ flowchart TB
|
|||||||
Loader[StreamingWorldLoader] --> State[AdtWaterLoadPipelineState]
|
Loader[StreamingWorldLoader] --> State[AdtWaterLoadPipelineState]
|
||||||
Loader --> Scheduler[RenderBudgetScheduler]
|
Loader --> Scheduler[RenderBudgetScheduler]
|
||||||
Loader --> Worker[WorkerThreadPool / ADTLoader]
|
Loader --> Worker[WorkerThreadPool / ADTLoader]
|
||||||
Loader --> Builder[ADTBuilder / SceneTree]
|
Loader --> Finalizer[AdtWaterSceneFinalizer]
|
||||||
|
Finalizer --> Builder[ADTBuilder / SceneTree]
|
||||||
Worker -->|publish only| State
|
Worker -->|publish only| State
|
||||||
State -. no dependency .-> Scheduler
|
State -. no dependency .-> Scheduler
|
||||||
State -. no dependency .-> Builder
|
State -. no dependency .-> Finalizer
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ownership, threading and resources
|
## Ownership, threading and resources
|
||||||
@@ -163,7 +165,8 @@ flowchart TB
|
|||||||
- Worker threads may call only `publish_result`; result observe/pop/clear also lock.
|
- Worker threads may call only `publish_result`; result observe/pop/clear also lock.
|
||||||
- Parsed water Dictionary identity is retained until main-thread pop.
|
- Parsed water Dictionary identity is retained until main-thread pop.
|
||||||
- Loader owns WorkerThreadPool task lifetime and must wait before orderly shutdown clear.
|
- Loader owns WorkerThreadPool task lifetime and must wait before orderly shutdown clear.
|
||||||
- Loader owns tile states, ADTBuilder, water Nodes and every render resource.
|
- Loader owns tile states and the tile subtree; `AdtWaterSceneFinalizer` performs
|
||||||
|
the main-thread ADTBuilder call and attachment without retaining Nodes.
|
||||||
- `clear` cannot cancel a worker; post-reset publication becomes a stale result
|
- `clear` cannot cancel a worker; post-reset publication becomes a stale result
|
||||||
and is discarded because no active task/tile ownership remains.
|
and is discarded because no active task/tile ownership remains.
|
||||||
|
|
||||||
@@ -211,8 +214,8 @@ versions are unchanged; no migration or rebuild is required.
|
|||||||
## Extension points
|
## Extension points
|
||||||
|
|
||||||
- ADT parse execution can later move behind a parser/job adapter without changing state.
|
- ADT parse execution can later move behind a parser/job adapter without changing state.
|
||||||
- Water scene materialization can be extracted separately because it owns Nodes
|
- Water scene materialization is now delegated to `AdtWaterSceneFinalizer`,
|
||||||
and main-thread effects rather than async bookkeeping.
|
independently of this async bookkeeping service.
|
||||||
|
|
||||||
## Capability status
|
## Capability status
|
||||||
|
|
||||||
@@ -220,7 +223,7 @@ versions are unchanged; no migration or rebuild is required.
|
|||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ADT water load pipeline state | Implemented extraction | FIFO/task/thread/source/timing verifier | Asset-backed traversal/leak evidence pending |
|
| ADT water load pipeline state | Implemented extraction | FIFO/task/thread/source/timing verifier | Asset-backed traversal/leak evidence pending |
|
||||||
| ADT liquid parsing | Existing/loader-owned adapter | Native ADTLoader and dry-run paths | MH2O/MCLQ fidelity fixtures pending |
|
| ADT liquid parsing | Existing/loader-owned adapter | Native ADTLoader and dry-run paths | MH2O/MCLQ fidelity fixtures pending |
|
||||||
| Water scene finalization | Existing/loader-owned | Scheduler/material/shutdown regressions | Separate materialization extraction possible |
|
| Water scene finalization | Implemented extraction | Dedicated synthetic scene/ownership verifier | Asset-backed traversal/hitch evidence pending |
|
||||||
|
|
||||||
## Known gaps and risks
|
## Known gaps and risks
|
||||||
|
|
||||||
@@ -235,13 +238,15 @@ versions are unchanged; no migration or rebuild is required.
|
|||||||
| Path | Responsibility |
|
| Path | Responsibility |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `src/render/liquid/adt_water_load_pipeline_state.gd` | Request/task/result bookkeeping and result mutex |
|
| `src/render/liquid/adt_water_load_pipeline_state.gd` | Request/task/result bookkeeping and result mutex |
|
||||||
| `src/scenes/streaming/streaming_world_loader.gd` | Parse task execution, permits, stale checks and Node finalization |
|
| `src/render/liquid/adt_water_scene_finalizer.gd` | Main-thread ADTBuilder call, attach and optional editor ownership |
|
||||||
|
| `src/scenes/streaming/streaming_world_loader.gd` | Parse task execution, permits, stale checks and tile loaded timing |
|
||||||
| `addons/mpq_extractor/loaders/adt_builder.gd` | ADT liquid geometry/material construction |
|
| `addons/mpq_extractor/loaders/adt_builder.gd` | ADT liquid geometry/material construction |
|
||||||
| `src/tools/verify_adt_water_load_pipeline_state.gd` | Lifecycle/thread/boundary/timing regression |
|
| `src/tools/verify_adt_water_load_pipeline_state.gd` | Lifecycle/thread/boundary/timing regression |
|
||||||
|
|
||||||
## Related decisions and references
|
## Related decisions and references
|
||||||
|
|
||||||
- [`world-renderer.md`](world-renderer.md)
|
- [`world-renderer.md`](world-renderer.md)
|
||||||
|
- [`adt-water-scene-finalizer.md`](adt-water-scene-finalizer.md)
|
||||||
- [`render-budget-scheduler.md`](render-budget-scheduler.md)
|
- [`render-budget-scheduler.md`](render-budget-scheduler.md)
|
||||||
- [`../../RENDER.md`](../../RENDER.md)
|
- [`../../RENDER.md`](../../RENDER.md)
|
||||||
- [`../../targets/roadmap/02-rendering-and-graphics.md`](../../targets/roadmap/02-rendering-and-graphics.md)
|
- [`../../targets/roadmap/02-rendering-and-graphics.md`](../../targets/roadmap/02-rendering-and-graphics.md)
|
||||||
|
|||||||
@@ -0,0 +1,232 @@
|
|||||||
|
# ADT Water Scene Finalizer
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|---|---|
|
||||||
|
| Status | Implemented extraction |
|
||||||
|
| Target/work package | M03 / `M03-RND-ADT-WATER-SCENE-FINALIZER-001` |
|
||||||
|
| Owners | Main-thread ADT water subtree build, attach and optional editor ownership |
|
||||||
|
| Last verified | Worktree `work/sindo-main-codex/m03-adt-water-scene-finalizer`, 2026-07-17 |
|
||||||
|
| Profiles/capabilities | Existing ADT MH2O/MCLQ scene output; profile-independent adapter |
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Provide one liquid-specific main-thread boundary for converting parsed ADT
|
||||||
|
water data through the existing `ADTBuilder`, attaching the resulting `Water`
|
||||||
|
subtree to a caller-owned tile root and assigning optional persisted Editor
|
||||||
|
ownership. The service is stateless and retains no Node or Resource.
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- Parse or validate MH2O/MCLQ binary structures.
|
||||||
|
- Replace ADTBuilder geometry, material or coordinate calculations.
|
||||||
|
- Own water request/task/result state, permits or concurrency.
|
||||||
|
- Validate tile/path/root freshness beyond receiving a valid root.
|
||||||
|
- Mark `water_loaded`, enable water or remove water subtrees.
|
||||||
|
|
||||||
|
## Context and boundaries
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
Parse[Parsed ADT Dictionary] --> Loader[StreamingWorldLoader]
|
||||||
|
Loader -->|validated data, origin, tile root| Finalizer[AdtWaterSceneFinalizer]
|
||||||
|
Finalizer --> Builder[ADTBuilder]
|
||||||
|
Builder --> Water[Water Node3D or null]
|
||||||
|
Water --> Finalizer
|
||||||
|
Finalizer -->|main-thread add_child| Tile[Caller-owned tile root]
|
||||||
|
Loader -->|after return| Loaded[water_loaded timing]
|
||||||
|
```
|
||||||
|
|
||||||
|
Allowed dependencies are `ADTBuilder` and Godot Node/mesh types needed to adopt
|
||||||
|
its output. WorkerThreadPool, scheduler, tile-state dictionaries, facade,
|
||||||
|
gameplay, network and editor plugin packages are forbidden.
|
||||||
|
|
||||||
|
## Public API
|
||||||
|
|
||||||
|
| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `attach_water_scene(water_data, tile_origin_godot_units, tile_root, editor_owner)` | Command/query | Build and attach one existing-format water subtree | Renderer main thread; returned Node is borrowed for tile lifetime | Empty data, invalid root or dry build returns null without attachment |
|
||||||
|
|
||||||
|
`editor_owner` is optional. When supplied it must be an ancestor suitable for
|
||||||
|
Godot `Node.owner`; ownership is recursively assigned to the generated subtree.
|
||||||
|
|
||||||
|
## Inputs and outputs
|
||||||
|
|
||||||
|
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| Input | Parsed ADT water-containing Dictionary | ADTLoader/raw tile path | Finalizer/ADTBuilder | Caller retains Dictionary; not mutated | One main-thread call |
|
||||||
|
| Input | Tile origin in Godot world units | Loader tile state/ADTBuilder | Finalizer | Value copy | One call |
|
||||||
|
| Input | Valid tile root | StreamingWorldLoader | Finalizer | Caller/SceneTree-owned | Must outlive call and attached subtree |
|
||||||
|
| Input | Optional edited scene root | Loader Editor policy | Finalizer | SceneTree-owned borrowed Node | One call |
|
||||||
|
| Output | Attached `Water` Node3D or null | Finalizer | Loader/SceneTree | Tile root owns attached Node | Tile subtree lifetime |
|
||||||
|
|
||||||
|
Side effects are limited to ADTBuilder mesh/material creation, `add_child` and
|
||||||
|
optional recursive `Node.owner` assignment. No cache, filesystem, task or tile
|
||||||
|
state is mutated.
|
||||||
|
|
||||||
|
## Data flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
Input[water data + Godot origin + tile root] --> Guard{Data and root valid?}
|
||||||
|
Guard -->|no| None[Return null; unchanged]
|
||||||
|
Guard -->|yes| Build[ADTBuilder.build_tile_water_scene]
|
||||||
|
Build --> Dry{Water root exists?}
|
||||||
|
Dry -->|no| None
|
||||||
|
Dry -->|yes| Attach[tile root add_child]
|
||||||
|
Attach --> Owner{Editor owner supplied?}
|
||||||
|
Owner -->|yes| Assign[Assign owner recursively]
|
||||||
|
Owner -->|no| Return[Return borrowed root]
|
||||||
|
Assign --> Return
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lifecycle/state
|
||||||
|
|
||||||
|
The service has no retained lifecycle. Each call moves one temporary builder
|
||||||
|
result through the following call-local states.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> Validating
|
||||||
|
Validating --> Rejected: empty data or invalid root
|
||||||
|
Validating --> Building: valid input
|
||||||
|
Building --> Dry: no geometry
|
||||||
|
Building --> Attached: Water root built
|
||||||
|
Attached --> EditorOwned: owner supplied
|
||||||
|
Attached --> Complete: no owner
|
||||||
|
EditorOwned --> Complete
|
||||||
|
Rejected --> [*]
|
||||||
|
Dry --> [*]
|
||||||
|
Complete --> [*]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Main sequence
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant Loader as StreamingWorldLoader main thread
|
||||||
|
participant Finalizer as AdtWaterSceneFinalizer
|
||||||
|
participant Builder as ADTBuilder
|
||||||
|
participant Tile as Tile root
|
||||||
|
Loader->>Finalizer: attach_water_scene(data, origin, tile, editor owner)
|
||||||
|
Finalizer->>Builder: build_tile_water_scene(data, origin)
|
||||||
|
Builder-->>Finalizer: Water root or null
|
||||||
|
alt Water root exists
|
||||||
|
Finalizer->>Tile: add_child(Water)
|
||||||
|
opt editor owner supplied
|
||||||
|
Finalizer->>Finalizer: assign owner recursively
|
||||||
|
end
|
||||||
|
Finalizer-->>Loader: borrowed Water root
|
||||||
|
else dry/invalid
|
||||||
|
Finalizer-->>Loader: null
|
||||||
|
end
|
||||||
|
Loader->>Loader: preserve existing water_loaded timing
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dependency diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
Loader[StreamingWorldLoader] --> Finalizer[AdtWaterSceneFinalizer]
|
||||||
|
Finalizer --> Builder[ADTBuilder]
|
||||||
|
Builder --> Material[WowLiquidMaterial]
|
||||||
|
Finalizer --> Scene[Godot SceneTree]
|
||||||
|
Pipeline[AdtWaterLoadPipelineState] --> Loader
|
||||||
|
Scheduler[RenderBudgetScheduler] --> Loader
|
||||||
|
Finalizer -. no dependency .-> Pipeline
|
||||||
|
Finalizer -. no dependency .-> Scheduler
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ownership, threading and resources
|
||||||
|
|
||||||
|
- The method is main-thread only because it creates Mesh/Material/Node objects
|
||||||
|
and mutates the SceneTree.
|
||||||
|
- `ADTBuilder` owns temporary construction. It frees an empty `Water` root and
|
||||||
|
returns null for dry/invalid liquid geometry.
|
||||||
|
- After `add_child`, the caller's tile subtree owns the returned Water root and
|
||||||
|
all MeshInstance children; the finalizer retains no references.
|
||||||
|
- Optional editor ownership affects serialization ownership only and does not
|
||||||
|
replace SceneTree lifetime ownership.
|
||||||
|
- Parsed Dictionaries are borrowed and not mutated.
|
||||||
|
|
||||||
|
## Errors, cancellation and recovery
|
||||||
|
|
||||||
|
| Failure | Detection | Behavior | Diagnostic | Recovery |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| Empty parsed data | Input guard | Return null, no builder call | Contract verifier | Loader preserves existing loaded timing |
|
||||||
|
| Missing/freed tile root | Input guard | Return null, no scene mutation | Contract verifier | Stale-result validation normally rejects earlier |
|
||||||
|
| Dry or malformed liquid arrays | ADTBuilder returns null | No attachment | Builder/shutdown regression | Reload after corrected source |
|
||||||
|
| Tile/path stale | Loader before call | Finalizer is not invoked | Existing loader behavior | Current tile may enqueue again |
|
||||||
|
| Shutdown/cancellation | Loader drains/cancels before call | No retained finalizer work | Shutdown verifier | New loader starts stateless |
|
||||||
|
|
||||||
|
## Configuration and capabilities
|
||||||
|
|
||||||
|
| Setting/capability | Default | Profile | Runtime mutable | Effect |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `enable_water` | Loader setting | Quality/custom | Yes | Gates both caller paths; not owned here |
|
||||||
|
| `water_finalize_ops_per_tick` | `1` | Quality/custom | Yes | Budgets async calls before finalizer |
|
||||||
|
| `editor_persist_generated_nodes` | `false` | Editor only | Yes | Supplies or omits editor owner |
|
||||||
|
|
||||||
|
## Persistence, cache and migration
|
||||||
|
|
||||||
|
The service writes no files and changes no cache/resource schema. Existing ADT,
|
||||||
|
terrain cache and liquid material versions remain valid; no rebuild or migration
|
||||||
|
is required. Persisted Editor ownership follows the loader's existing opt-in.
|
||||||
|
|
||||||
|
## Diagnostics and observability
|
||||||
|
|
||||||
|
- Logs: none; existing loader/builder diagnostics remain authoritative.
|
||||||
|
- Metrics: no independent counters; existing water queue/finalize metrics remain.
|
||||||
|
- Debug views: generated `Water/Liquid_<id>` names remain unchanged.
|
||||||
|
- Correlation IDs: tile/path correlation stays in loader pipeline state.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- `verify_adt_water_scene_finalizer.gd`: empty/invalid/dry guards, one-cell
|
||||||
|
geometry, attachment, recursive owner, loader delegation and bounded timing.
|
||||||
|
- `verify_adt_water_load_pipeline_state.gd`: adjacent async ownership and loaded timing.
|
||||||
|
- Renderer material and shutdown verifiers cover material construction and dry-root cleanup.
|
||||||
|
- Fidelity evidence is the unchanged ADTBuilder implementation and unchanged two
|
||||||
|
loader call positions; no new original-client liquid parity claim is made.
|
||||||
|
- Performance budget: 100 empty calls under one second.
|
||||||
|
|
||||||
|
## Extension points
|
||||||
|
|
||||||
|
- A future liquid renderer may replace the internal builder only after paired
|
||||||
|
MH2O/MCLQ fixtures establish equivalent geometry/material behavior.
|
||||||
|
- Removal/eviction remains ordinary tile subtree ownership and needs no parallel API.
|
||||||
|
|
||||||
|
## Capability status
|
||||||
|
|
||||||
|
| Capability | Status | Evidence | Gap/next step |
|
||||||
|
|---|---|---|---|
|
||||||
|
| ADT water scene finalization seam | Implemented extraction | Synthetic geometry/attach/owner/source verifier | Asset-backed traversal and hitch metrics pending |
|
||||||
|
| ADT liquid geometry/materials | Existing implementation | ADTBuilder/material/checkpoint evidence | MH2O/MCLQ and original-client parity incomplete |
|
||||||
|
| Async water scheduling | Existing extracted state | Water pipeline verifier | Active worker interruption remains loader-owned |
|
||||||
|
|
||||||
|
## Known gaps and risks
|
||||||
|
|
||||||
|
- The service intentionally wraps the existing Dictionary-based ADTBuilder boundary.
|
||||||
|
- It does not verify that `editor_owner` is an ancestor; the loader supplies the
|
||||||
|
edited scene root under the existing policy.
|
||||||
|
- Mesh/material creation remains synchronous main-thread work behind the existing permit.
|
||||||
|
- No proprietary liquid corpus, long traversal leak run, p95/p99 or paired capture is included.
|
||||||
|
|
||||||
|
## Source map
|
||||||
|
|
||||||
|
| Path | Responsibility |
|
||||||
|
|---|---|
|
||||||
|
| `src/render/liquid/adt_water_scene_finalizer.gd` | Main-thread build, attach and optional recursive editor ownership |
|
||||||
|
| `addons/mpq_extractor/loaders/adt_builder.gd` | Existing ADT liquid geometry/material creation and dry-root cleanup |
|
||||||
|
| `src/render/liquid/adt_water_load_pipeline_state.gd` | Pending/task/result state before finalization |
|
||||||
|
| `src/scenes/streaming/streaming_world_loader.gd` | Permits, stale checks, tile state and finalizer calls |
|
||||||
|
| `src/tools/verify_adt_water_scene_finalizer.gd` | Synthetic scene/ownership/boundary/timing regression |
|
||||||
|
|
||||||
|
## Related decisions and references
|
||||||
|
|
||||||
|
- [`adt-water-load-pipeline-state.md`](adt-water-load-pipeline-state.md)
|
||||||
|
- [`world-renderer.md`](world-renderer.md)
|
||||||
|
- [`render-budget-scheduler.md`](render-budget-scheduler.md)
|
||||||
|
- [`../../RENDER.md`](../../RENDER.md)
|
||||||
|
- [`../../targets/roadmap/02-rendering-and-graphics.md`](../../targets/roadmap/02-rendering-and-graphics.md)
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
| Status | Partial |
|
| Status | Partial |
|
||||||
| Target/work package | M00 baseline; `M01-RND-STREAMING-FOCUS-001`; `M01-QAR-SERVER-SPAWN-RENDERER-001`; M03 facade/planner/scheduler/internal-access/ground/environment/entity packages; M03 terrain packages; M03 M2 packages; M03 WMO placement package |
|
| Target/work package | M00 baseline; `M01-RND-STREAMING-FOCUS-001`; `M01-QAR-SERVER-SPAWN-RENDERER-001`; M03 facade/planner/scheduler/internal-access/ground/environment/entity packages; M03 terrain packages; M03 M2 packages; M03 WMO placement package |
|
||||||
| Owners | Renderer workstream / milestone integrator |
|
| Owners | Renderer workstream / milestone integrator |
|
||||||
| Last verified | Worktree `work/sindo-main-codex/m03-adt-water-load-pipeline`, 2026-07-17 |
|
| Last verified | Worktree `work/sindo-main-codex/m03-adt-water-scene-finalizer`, 2026-07-17 |
|
||||||
| Profiles/capabilities | `Performance`, `Balanced`, `High`, `Custom`; Blizzlike fidelity incomplete |
|
| Profiles/capabilities | `Performance`, `Balanced`, `High`, `Custom`; Blizzlike fidelity incomplete |
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
@@ -139,6 +139,7 @@ from externally reading/writing loader-private queue, task, cache and tile-state
|
|||||||
| `WmoRenderResourceCacheState` | Internal WMO cache-state service | Owns validated Resources, negative entries and pending cache paths | Renderer main thread; map/cache session | Invalid/occupied request and unknown completion are rejected |
|
| `WmoRenderResourceCacheState` | Internal WMO cache-state service | Owns validated Resources, negative entries and pending cache paths | Renderer main thread; map/cache session | Invalid/occupied request and unknown completion are rejected |
|
||||||
| `WmoSceneResourceCacheState` | Internal WMO cache-state service | Owns validated PackedScenes, negative entries and pending `.tscn` paths | Renderer main thread; map/cache session | Direct missing and terminal request transitions remain distinct |
|
| `WmoSceneResourceCacheState` | Internal WMO cache-state service | Owns validated PackedScenes, negative entries and pending `.tscn` paths | Renderer main thread; map/cache session | Direct missing and terminal request transitions remain distinct |
|
||||||
| `AdtWaterLoadPipelineState` | Internal liquid async-state service | Owns ADT water FIFO/dedupe, active task IDs and mutex result mailbox | Main-thread state; worker result publication | Invalid/duplicate requests rejected; clear does not interrupt workers |
|
| `AdtWaterLoadPipelineState` | Internal liquid async-state service | Owns ADT water FIFO/dedupe, active task IDs and mutex result mailbox | Main-thread state; worker result publication | Invalid/duplicate requests rejected; clear does not interrupt workers |
|
||||||
|
| `AdtWaterSceneFinalizer.attach_water_scene` | Internal liquid main-thread service | Builds and attaches one existing-format ADT Water subtree | Main thread; stateless, returned Node tile-owned | Empty/invalid/dry input returns null without attachment |
|
||||||
|
|
||||||
Публичным contract не считаются `StreamingWorldLoader` methods/properties,
|
Публичным contract не считаются `StreamingWorldLoader` methods/properties,
|
||||||
внутренние dictionaries, queues, job records и generated node names. Scene-owned
|
внутренние dictionaries, queues, job records и generated node names. Scene-owned
|
||||||
@@ -361,7 +362,9 @@ sequenceDiagram
|
|||||||
- `AdtWaterLoadPipelineState` owns pending request order/deduplication, opaque
|
- `AdtWaterLoadPipelineState` owns pending request order/deduplication, opaque
|
||||||
active task IDs and the worker-safe parsed-result mailbox. The loader retains
|
active task IDs and the worker-safe parsed-result mailbox. The loader retains
|
||||||
WorkerThreadPool start/wait, ADTLoader parsing, concurrency/finalize permits,
|
WorkerThreadPool start/wait, ADTLoader parsing, concurrency/finalize permits,
|
||||||
stale tile/path/root checks and ADTBuilder/Node finalization.
|
stale tile/path/root checks and `water_loaded` timing. `AdtWaterSceneFinalizer`
|
||||||
|
performs the existing ADTBuilder call, tile attach and optional recursive
|
||||||
|
Editor ownership on the main thread without retaining the generated subtree.
|
||||||
- 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
|
||||||
@@ -561,6 +564,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
|
|||||||
| `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/terrain/terrain_quality_mesh_cache.gd` | Full-quality terrain revisit Mesh retention and LRU ownership |
|
| `src/render/terrain/terrain_quality_mesh_cache.gd` | Full-quality terrain revisit Mesh retention and LRU ownership |
|
||||||
| `src/render/liquid/adt_water_load_pipeline_state.gd` | ADT water request/task/result bookkeeping and worker-safe mailbox |
|
| `src/render/liquid/adt_water_load_pipeline_state.gd` | ADT water request/task/result bookkeeping and worker-safe mailbox |
|
||||||
|
| `src/render/liquid/adt_water_scene_finalizer.gd` | Main-thread ADT water build, tile attachment and optional editor ownership |
|
||||||
| `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 |
|
||||||
| `src/render/streaming/streaming_target_plan.gd` | Immutable planner result with read-only tile-key sets |
|
| `src/render/streaming/streaming_target_plan.gd` | Immutable planner result with read-only tile-key sets |
|
||||||
@@ -574,6 +578,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m
|
|||||||
| `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_terrain_quality_mesh_cache.gd` | Terrain cache admission, LRU, ownership and loader-boundary regression |
|
| `src/tools/verify_terrain_quality_mesh_cache.gd` | Terrain cache admission, LRU, ownership and loader-boundary regression |
|
||||||
| `src/tools/verify_adt_water_load_pipeline_state.gd` | ADT water FIFO/task/thread/boundary/timing regression |
|
| `src/tools/verify_adt_water_load_pipeline_state.gd` | ADT water FIFO/task/thread/boundary/timing regression |
|
||||||
|
| `src/tools/verify_adt_water_scene_finalizer.gd` | Synthetic ADT water scene/ownership/boundary/timing 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 |
|
||||||
| `src/tools/verify_renderer_internal_access.gd` | Gameplay/EditorPlugin/registered renderer-tool boundary gate derived from private streamer fields |
|
| `src/tools/verify_renderer_internal_access.gd` | Gameplay/EditorPlugin/registered renderer-tool boundary gate derived from private streamer fields |
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
class_name AdtWaterSceneFinalizer
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
## Builds and attaches one ADT water subtree on the renderer main thread. The
|
||||||
|
## supplied tile root owns the returned subtree; this service retains no state.
|
||||||
|
|
||||||
|
const ADT_BUILDER_SCRIPT := preload("res://addons/mpq_extractor/loaders/adt_builder.gd")
|
||||||
|
|
||||||
|
|
||||||
|
## Builds water from parsed ADT data and attaches it once to [param tile_root].
|
||||||
|
## [param tile_origin_godot_units] is the existing Godot-world tile origin used
|
||||||
|
## by [ADTBuilder]. When [param editor_owner] is non-null and is an ancestor,
|
||||||
|
## ownership is assigned recursively for persisted Editor previews. Returns the
|
||||||
|
## attached borrowed root, or null for empty/invalid input or dry ADT data.
|
||||||
|
## This method mutates the SceneTree and must run on the main thread.
|
||||||
|
func attach_water_scene(
|
||||||
|
water_data: Dictionary,
|
||||||
|
tile_origin_godot_units: Vector3,
|
||||||
|
tile_root: Node,
|
||||||
|
editor_owner: Node = null) -> Node3D:
|
||||||
|
if water_data.is_empty() or tile_root == null or not is_instance_valid(tile_root):
|
||||||
|
return null
|
||||||
|
|
||||||
|
var water_root: Node3D = ADT_BUILDER_SCRIPT.build_tile_water_scene(
|
||||||
|
water_data,
|
||||||
|
tile_origin_godot_units
|
||||||
|
)
|
||||||
|
if water_root == null:
|
||||||
|
return null
|
||||||
|
|
||||||
|
tile_root.add_child(water_root)
|
||||||
|
if editor_owner != null and is_instance_valid(editor_owner):
|
||||||
|
_assign_owner_recursive(water_root, editor_owner)
|
||||||
|
return water_root
|
||||||
|
|
||||||
|
|
||||||
|
func _assign_owner_recursive(generated_node: Node, editor_owner: Node) -> void:
|
||||||
|
generated_node.owner = editor_owner
|
||||||
|
for child in generated_node.get_children():
|
||||||
|
_assign_owner_recursive(child, editor_owner)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ck4sdc8a3kg00
|
||||||
@@ -45,6 +45,9 @@ const TERRAIN_CHUNK_GEOMETRY_QUEUE_PLANNER_SCRIPT := preload(
|
|||||||
const ADT_WATER_LOAD_PIPELINE_STATE_SCRIPT := preload(
|
const ADT_WATER_LOAD_PIPELINE_STATE_SCRIPT := preload(
|
||||||
"res://src/render/liquid/adt_water_load_pipeline_state.gd"
|
"res://src/render/liquid/adt_water_load_pipeline_state.gd"
|
||||||
)
|
)
|
||||||
|
const ADT_WATER_SCENE_FINALIZER_SCRIPT := preload(
|
||||||
|
"res://src/render/liquid/adt_water_scene_finalizer.gd"
|
||||||
|
)
|
||||||
const M2_UNIQUE_PLACEMENT_REGISTRY_SCRIPT := preload(
|
const M2_UNIQUE_PLACEMENT_REGISTRY_SCRIPT := preload(
|
||||||
"res://src/render/m2/m2_unique_placement_registry.gd"
|
"res://src/render/m2/m2_unique_placement_registry.gd"
|
||||||
)
|
)
|
||||||
@@ -260,6 +263,7 @@ var _terrain_splat_tasks: Dictionary = {}
|
|||||||
var _terrain_splat_result_mutex := Mutex.new()
|
var _terrain_splat_result_mutex := Mutex.new()
|
||||||
var _terrain_splat_result_queue: Array = []
|
var _terrain_splat_result_queue: Array = []
|
||||||
var _adt_water_load_pipeline_state := ADT_WATER_LOAD_PIPELINE_STATE_SCRIPT.new()
|
var _adt_water_load_pipeline_state := ADT_WATER_LOAD_PIPELINE_STATE_SCRIPT.new()
|
||||||
|
var _adt_water_scene_finalizer := ADT_WATER_SCENE_FINALIZER_SCRIPT.new()
|
||||||
var _tile_result_mutex := Mutex.new()
|
var _tile_result_mutex := Mutex.new()
|
||||||
var _tile_result_queue: Array = []
|
var _tile_result_queue: Array = []
|
||||||
var _shared_tex_cache: Dictionary = {}
|
var _shared_tex_cache: Dictionary = {}
|
||||||
@@ -2294,10 +2298,12 @@ func _drain_water_load_results() -> void:
|
|||||||
var data: Dictionary = result.get("data", {})
|
var data: Dictionary = result.get("data", {})
|
||||||
if not data.is_empty():
|
if not data.is_empty():
|
||||||
var origin: Vector3 = state.get("origin", Vector3.ZERO)
|
var origin: Vector3 = state.get("origin", Vector3.ZERO)
|
||||||
var water_root: Node3D = _builder.build_tile_water_scene(data, origin)
|
_adt_water_scene_finalizer.attach_water_scene(
|
||||||
if water_root:
|
data,
|
||||||
tile_root.add_child(water_root)
|
origin,
|
||||||
_set_editor_owner_recursive(water_root)
|
tile_root,
|
||||||
|
_editor_owner_for_generated_nodes()
|
||||||
|
)
|
||||||
|
|
||||||
state["water_loaded"] = true
|
state["water_loaded"] = true
|
||||||
_tile_states[key] = state
|
_tile_states[key] = state
|
||||||
@@ -2448,10 +2454,12 @@ func _finalize_loaded_tile(request: Dictionary, data: Dictionary) -> void:
|
|||||||
tile_root.position = tile_origin
|
tile_root.position = tile_origin
|
||||||
|
|
||||||
if enable_water:
|
if enable_water:
|
||||||
var water_root: Node3D = _builder.build_tile_water_scene(data, tile_origin)
|
_adt_water_scene_finalizer.attach_water_scene(
|
||||||
if water_root:
|
data,
|
||||||
tile_root.add_child(water_root)
|
tile_origin,
|
||||||
_set_editor_owner_recursive(water_root)
|
tile_root,
|
||||||
|
_editor_owner_for_generated_nodes()
|
||||||
|
)
|
||||||
if enable_m2_placeholders:
|
if enable_m2_placeholders:
|
||||||
_build_tile_m2_placeholders(
|
_build_tile_m2_placeholders(
|
||||||
tile_root,
|
tile_root,
|
||||||
@@ -5421,12 +5429,7 @@ func _tile_key(tx: int, ty: int) -> String:
|
|||||||
|
|
||||||
|
|
||||||
func _set_editor_owner_recursive(node: Node) -> void:
|
func _set_editor_owner_recursive(node: Node) -> void:
|
||||||
if not Engine.is_editor_hint():
|
var edited_root := _editor_owner_for_generated_nodes()
|
||||||
return
|
|
||||||
if not editor_persist_generated_nodes:
|
|
||||||
return
|
|
||||||
|
|
||||||
var edited_root := get_tree().edited_scene_root
|
|
||||||
if edited_root == null:
|
if edited_root == null:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -5435,6 +5438,12 @@ func _set_editor_owner_recursive(node: Node) -> void:
|
|||||||
_set_editor_owner_recursive(child)
|
_set_editor_owner_recursive(child)
|
||||||
|
|
||||||
|
|
||||||
|
func _editor_owner_for_generated_nodes() -> Node:
|
||||||
|
if not Engine.is_editor_hint() or not editor_persist_generated_nodes:
|
||||||
|
return null
|
||||||
|
return get_tree().edited_scene_root
|
||||||
|
|
||||||
|
|
||||||
func _make_editor_signature() -> String:
|
func _make_editor_signature() -> String:
|
||||||
var values := [
|
var values := [
|
||||||
extracted_dir,
|
extracted_dir,
|
||||||
|
|||||||
@@ -241,8 +241,7 @@ func _verify_ownership_boundaries(failures: Array[String]) -> void:
|
|||||||
"ClassDB.instantiate(\"ADTLoader\")",
|
"ClassDB.instantiate(\"ADTLoader\")",
|
||||||
"WorkerThreadPool.add_task(_load_tile_water_task.bind(key, path))",
|
"WorkerThreadPool.add_task(_load_tile_water_task.bind(key, path))",
|
||||||
"RENDER_BUDGET_SCHEDULER_SCRIPT.WATER_FINALIZE",
|
"RENDER_BUDGET_SCHEDULER_SCRIPT.WATER_FINALIZE",
|
||||||
"_builder.build_tile_water_scene(data, origin)",
|
"_adt_water_scene_finalizer.attach_water_scene(",
|
||||||
"tile_root.add_child(water_root)",
|
|
||||||
"state[\"water_loaded\"] = true",
|
"state[\"water_loaded\"] = true",
|
||||||
]:
|
]:
|
||||||
_expect_true(loader_source.contains(retained_loader_rule), "loader retains %s" % retained_loader_rule, failures)
|
_expect_true(loader_source.contains(retained_loader_rule), "loader retains %s" % retained_loader_rule, failures)
|
||||||
|
|||||||
@@ -0,0 +1,194 @@
|
|||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
## Synthetic main-thread scene, ownership, boundary and timing regression for
|
||||||
|
## ADT water finalization.
|
||||||
|
|
||||||
|
const FINALIZER_SCRIPT := preload("res://src/render/liquid/adt_water_scene_finalizer.gd")
|
||||||
|
const FINALIZER_PATH := "res://src/render/liquid/adt_water_scene_finalizer.gd"
|
||||||
|
const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd"
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
var failures: Array[String] = []
|
||||||
|
_verify_invalid_and_dry_input(failures)
|
||||||
|
_verify_build_attach_geometry_and_owner(failures)
|
||||||
|
_verify_ownership_boundaries(failures)
|
||||||
|
var elapsed_milliseconds := _verify_bounded_timing(failures)
|
||||||
|
if not failures.is_empty():
|
||||||
|
for failure in failures:
|
||||||
|
push_error("ADT_WATER_SCENE_FINALIZER: %s" % failure)
|
||||||
|
quit(1)
|
||||||
|
return
|
||||||
|
print(
|
||||||
|
"ADT_WATER_SCENE_FINALIZER PASS cases=8 iterations=100 elapsed_ms=%.3f"
|
||||||
|
% elapsed_milliseconds
|
||||||
|
)
|
||||||
|
quit(0)
|
||||||
|
|
||||||
|
|
||||||
|
func _verify_invalid_and_dry_input(failures: Array[String]) -> void:
|
||||||
|
var finalizer: RefCounted = FINALIZER_SCRIPT.new()
|
||||||
|
var tile_root := Node3D.new()
|
||||||
|
_expect_null(
|
||||||
|
finalizer.call("attach_water_scene", {}, Vector3.ZERO, tile_root, null),
|
||||||
|
"empty water data returns null",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_equal(tile_root.get_child_count(), 0, "empty data does not mutate tile", failures)
|
||||||
|
_expect_null(
|
||||||
|
finalizer.call("attach_water_scene", _synthetic_water_data(), Vector3.ZERO, null, null),
|
||||||
|
"missing tile root returns null",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_null(
|
||||||
|
finalizer.call(
|
||||||
|
"attach_water_scene",
|
||||||
|
{"chunks": [{"origin": Vector3.ZERO, "liquids": []}]},
|
||||||
|
Vector3.ZERO,
|
||||||
|
tile_root,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
"dry parsed ADT returns null",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_equal(tile_root.get_child_count(), 0, "dry data does not mutate tile", failures)
|
||||||
|
tile_root.free()
|
||||||
|
|
||||||
|
|
||||||
|
func _verify_build_attach_geometry_and_owner(failures: Array[String]) -> void:
|
||||||
|
var finalizer: RefCounted = FINALIZER_SCRIPT.new()
|
||||||
|
var editor_scene_root := Node3D.new()
|
||||||
|
var tile_root := Node3D.new()
|
||||||
|
get_root().add_child(editor_scene_root)
|
||||||
|
editor_scene_root.add_child(tile_root)
|
||||||
|
|
||||||
|
var tile_origin := Vector3(10.0, 20.0, 30.0)
|
||||||
|
var water_root: Node3D = finalizer.call(
|
||||||
|
"attach_water_scene",
|
||||||
|
_synthetic_water_data(tile_origin),
|
||||||
|
tile_origin,
|
||||||
|
tile_root,
|
||||||
|
editor_scene_root
|
||||||
|
)
|
||||||
|
_expect_not_null(water_root, "synthetic liquid builds a water root", failures)
|
||||||
|
if water_root != null:
|
||||||
|
_expect_true(water_root.get_parent() == tile_root, "water root attached once", failures)
|
||||||
|
_expect_equal(tile_root.get_child_count(), 1, "tile owns one water root", failures)
|
||||||
|
_expect_true(water_root.owner == editor_scene_root, "water root editor owner", failures)
|
||||||
|
_expect_equal(water_root.get_child_count(), 1, "one liquid surface grouped", failures)
|
||||||
|
if water_root.get_child_count() == 1:
|
||||||
|
var liquid_mesh_instance := water_root.get_child(0) as MeshInstance3D
|
||||||
|
_expect_not_null(liquid_mesh_instance, "liquid child is MeshInstance3D", failures)
|
||||||
|
if liquid_mesh_instance != null:
|
||||||
|
_expect_true(
|
||||||
|
liquid_mesh_instance.owner == editor_scene_root,
|
||||||
|
"liquid child editor owner",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
var liquid_mesh := liquid_mesh_instance.mesh as ArrayMesh
|
||||||
|
_expect_not_null(liquid_mesh, "liquid surface has ArrayMesh", failures)
|
||||||
|
if liquid_mesh != null:
|
||||||
|
_expect_equal(
|
||||||
|
liquid_mesh.surface_get_array_len(0),
|
||||||
|
4,
|
||||||
|
"one enabled liquid cell has four vertices",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_equal(
|
||||||
|
liquid_mesh.surface_get_array_index_len(0),
|
||||||
|
6,
|
||||||
|
"one enabled liquid cell has six indices",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
editor_scene_root.free()
|
||||||
|
|
||||||
|
|
||||||
|
func _verify_ownership_boundaries(failures: Array[String]) -> void:
|
||||||
|
var finalizer_source := FileAccess.get_file_as_string(FINALIZER_PATH)
|
||||||
|
var loader_source := FileAccess.get_file_as_string(LOADER_PATH)
|
||||||
|
_expect_true(
|
||||||
|
finalizer_source.contains("ADT_BUILDER_SCRIPT.build_tile_water_scene"),
|
||||||
|
"finalizer retains existing ADTBuilder implementation",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_true(
|
||||||
|
finalizer_source.contains("tile_root.add_child(water_root)"),
|
||||||
|
"finalizer owns water subtree attachment",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_equal(
|
||||||
|
loader_source.count("_adt_water_scene_finalizer.attach_water_scene("),
|
||||||
|
2,
|
||||||
|
"both loader water paths delegate finalization",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_false(
|
||||||
|
loader_source.contains("_builder.build_tile_water_scene"),
|
||||||
|
"loader no longer builds water scenes directly",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_true(
|
||||||
|
loader_source.contains("state[\"water_loaded\"] = true"),
|
||||||
|
"loader retains water-loaded timing",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
_expect_true(
|
||||||
|
loader_source.contains("WATER_FINALIZE"),
|
||||||
|
"loader retains finalization permit ownership",
|
||||||
|
failures
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _verify_bounded_timing(failures: Array[String]) -> float:
|
||||||
|
var finalizer: RefCounted = FINALIZER_SCRIPT.new()
|
||||||
|
var tile_root := Node3D.new()
|
||||||
|
var started_microseconds := Time.get_ticks_usec()
|
||||||
|
for _iteration in range(100):
|
||||||
|
finalizer.call("attach_water_scene", {}, Vector3.ZERO, tile_root, null)
|
||||||
|
var elapsed_milliseconds := float(Time.get_ticks_usec() - started_microseconds) / 1000.0
|
||||||
|
_expect_true(elapsed_milliseconds < 1000.0, "100 empty attempts under 1 second", failures)
|
||||||
|
_expect_equal(tile_root.get_child_count(), 0, "timing loop creates no nodes", failures)
|
||||||
|
tile_root.free()
|
||||||
|
return elapsed_milliseconds
|
||||||
|
|
||||||
|
|
||||||
|
func _synthetic_water_data(tile_origin: Vector3 = Vector3.ZERO) -> Dictionary:
|
||||||
|
var liquid_mask := PackedByteArray()
|
||||||
|
liquid_mask.resize(64)
|
||||||
|
liquid_mask.fill(0)
|
||||||
|
liquid_mask[0] = 1
|
||||||
|
var liquid_heights := PackedFloat32Array()
|
||||||
|
liquid_heights.resize(81)
|
||||||
|
liquid_heights.fill(tile_origin.y + 5.0)
|
||||||
|
return {
|
||||||
|
"chunks": [{
|
||||||
|
"origin": tile_origin,
|
||||||
|
"liquids": [{
|
||||||
|
"liquid_id": 7,
|
||||||
|
"mask": liquid_mask,
|
||||||
|
"heights": liquid_heights,
|
||||||
|
}],
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func _expect_true(condition: bool, label: String, failures: Array[String]) -> void:
|
||||||
|
if not condition:
|
||||||
|
failures.append(label)
|
||||||
|
|
||||||
|
|
||||||
|
func _expect_false(condition: bool, label: String, failures: Array[String]) -> void:
|
||||||
|
_expect_true(not condition, label, failures)
|
||||||
|
|
||||||
|
|
||||||
|
func _expect_null(value: Variant, label: String, failures: Array[String]) -> void:
|
||||||
|
_expect_true(value == null, label, failures)
|
||||||
|
|
||||||
|
|
||||||
|
func _expect_not_null(value: Variant, label: String, failures: Array[String]) -> void:
|
||||||
|
_expect_true(value != null, label, failures)
|
||||||
|
|
||||||
|
|
||||||
|
func _expect_equal(actual: int, expected: int, label: String, failures: Array[String]) -> void:
|
||||||
|
if actual != expected:
|
||||||
|
failures.append("%s expected=%d actual=%d" % [label, expected, actual])
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://c1gqfpxg7ajsh
|
||||||
@@ -27,7 +27,7 @@ Runtime и Editor используют facade; planner/scheduler тестиру
|
|||||||
## Evidence
|
## Evidence
|
||||||
|
|
||||||
- Date: 2026-07-17
|
- Date: 2026-07-17
|
||||||
- Revision/worktree: master merges `7ece2ab`, `7e35de7`, `80cb084`, `d6e5b53`, `c69abd6`, `606770c`, `630a0c1`, `f36fabb`, `24aef13`, `2342430`, `396be5e`, `f88bf97`, `3f84717`, `d2cb52f`, `f9e5a4f`, `c06aed5`, `a878e7c`, `60603e1`, `b4955d6`, `ada0fd9`, `f470775`;
|
- Revision/worktree: master merges `7ece2ab`, `7e35de7`, `80cb084`, `d6e5b53`, `c69abd6`, `606770c`, `630a0c1`, `f36fabb`, `24aef13`, `2342430`, `396be5e`, `f88bf97`, `3f84717`, `d2cb52f`, `f9e5a4f`, `c06aed5`, `a878e7c`, `60603e1`, `b4955d6`, `ada0fd9`, `f470775`, `874fd0f`;
|
||||||
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-ENVIRONMENT-001`,
|
`M03-RND-FACADE-GROUND-QUERY-001`, `M03-RND-FACADE-ENVIRONMENT-001`,
|
||||||
`M03-RND-FACADE-ENTITY-001`, `M03-RND-TERRAIN-CACHE-SERVICE-001`,
|
`M03-RND-FACADE-ENTITY-001`, `M03-RND-TERRAIN-CACHE-SERVICE-001`,
|
||||||
@@ -42,7 +42,8 @@ Runtime и Editor используют facade; planner/scheduler тестиру
|
|||||||
`M03-RND-WMO-RENDER-BUILD-QUEUE-001`,
|
`M03-RND-WMO-RENDER-BUILD-QUEUE-001`,
|
||||||
`M03-RND-WMO-RENDER-RESOURCE-CACHE-001`,
|
`M03-RND-WMO-RENDER-RESOURCE-CACHE-001`,
|
||||||
`M03-RND-WMO-SCENE-RESOURCE-CACHE-001`,
|
`M03-RND-WMO-SCENE-RESOURCE-CACHE-001`,
|
||||||
`M03-RND-ADT-WATER-LOAD-PIPELINE-001`
|
`M03-RND-ADT-WATER-LOAD-PIPELINE-001`,
|
||||||
|
`M03-RND-ADT-WATER-SCENE-FINALIZER-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
|
||||||
@@ -117,6 +118,14 @@ Runtime и Editor используют facade; planner/scheduler тестиру
|
|||||||
checkpoint dry-run retained `7/7` plans. Post-merge water state (`86.935ms`),
|
checkpoint dry-run retained `7/7` plans. Post-merge water state (`86.935ms`),
|
||||||
shutdown, renderer materials, facade, internal-access `36`, `7/7` manifest,
|
shutdown, renderer materials, facade, internal-access `36`, `7/7` manifest,
|
||||||
documentation and coordination gates remained green.
|
documentation and coordination gates remained green.
|
||||||
|
ADT water scene finalizer passed `cases=8 iterations=100 elapsed_ms=0.042`
|
||||||
|
after an initial `0.024ms` run; synthetic data produced one four-vertex/
|
||||||
|
six-index liquid surface with exact tile attachment and recursive editor owner.
|
||||||
|
Water pipeline, WMO/M2/terrain/facade/scheduler/streaming/coordinate, material,
|
||||||
|
shutdown and 32 headless contract regressions passed; checkpoint dry-run
|
||||||
|
retained `7/7` plans. Post-merge finalizer (`0.025ms`), water pipeline
|
||||||
|
(`98.398ms`), shutdown, materials, facade, internal-access `36`, `7/7`
|
||||||
|
manifest, documentation and coordination gates remained green.
|
||||||
M02 terrain-query regression
|
M02 terrain-query regression
|
||||||
remained green (13 pre-existing expired M00 claim warnings).
|
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
|
||||||
@@ -172,7 +181,11 @@ Runtime и Editor используют facade; planner/scheduler тестиру
|
|||||||
result publication order are unchanged, and the mutex remains limited to the
|
result publication order are unchanged, and the mutex remains limited to the
|
||||||
worker/main-thread mailbox. The loader still owns ADT parsing, concurrency and
|
worker/main-thread mailbox. The loader still owns ADT parsing, concurrency and
|
||||||
profile limits, stale tile/path/root rejection, `WATER_FINALIZE` permits,
|
profile limits, stale tile/path/root rejection, `WATER_FINALIZE` permits,
|
||||||
water Node construction/attachment and `water_loaded` timing.
|
tile subtree lifetime and `water_loaded` timing.
|
||||||
|
Both raw-tile and delayed cached-tile water paths now call the same stateless
|
||||||
|
finalizer. It invokes the unchanged `ADTBuilder.build_tile_water_scene`,
|
||||||
|
attaches the returned root once and applies the existing optional recursive
|
||||||
|
Editor ownership; tile subtree lifetime and dry-root cleanup are 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;
|
||||||
@@ -196,6 +209,7 @@ Runtime и Editor используют facade; planner/scheduler тестиру
|
|||||||
validation/reset adapters,
|
validation/reset adapters,
|
||||||
ADT water pending/task/result pipeline state and loader enqueue/start/publish/
|
ADT water pending/task/result pipeline state and loader enqueue/start/publish/
|
||||||
drain/release/reset/shutdown/metrics adapters,
|
drain/release/reset/shutdown/metrics adapters,
|
||||||
|
stateless ADT water scene finalizer and both loader build/attach adapters,
|
||||||
expanded facade/internal-access/coordinate verifiers; work-package claims and this evidence.
|
expanded facade/internal-access/coordinate verifiers; work-package claims and this evidence.
|
||||||
- Remaining risks: worker concurrency and stale-result validation remain
|
- Remaining risks: worker concurrency and stale-result validation remain
|
||||||
streamer-owned; cancellation stops new permits but does not interrupt
|
streamer-owned; cancellation stops new permits but does not interrupt
|
||||||
@@ -213,7 +227,8 @@ Runtime и Editor используют facade; planner/scheduler тестиру
|
|||||||
WMO ResourceLoader/FileAccess I/O, live fallback and group materialization
|
WMO ResourceLoader/FileAccess I/O, live fallback and group materialization
|
||||||
remain in the loader;
|
remain in the loader;
|
||||||
asset-backed WMO placement/portal/material/leak/p95/p99 evidence remains pending;
|
asset-backed WMO placement/portal/material/leak/p95/p99 evidence remains pending;
|
||||||
ADT water parsing, main-thread materialization and active worker interruption
|
ADT water parsing and active worker interruption remain loader-owned;
|
||||||
remain loader-owned, and asset-backed MH2O/MCLQ traversal/leak/p95/p99/
|
materialization is separated but remains synchronous main-thread work behind
|
||||||
|
the existing permit, and asset-backed MH2O/MCLQ traversal/leak/p95/p99/
|
||||||
original-client evidence is pending; M03 still needs further terrain/M2/WMO/
|
original-client evidence is pending; M03 still needs further terrain/M2/WMO/
|
||||||
liquid service extraction and dependency/performance acceptance.
|
liquid service extraction and dependency/performance acceptance.
|
||||||
|
|||||||
Reference in New Issue
Block a user