From 9408d887bab201cfd61acc1087e01813c0562a82 Mon Sep 17 00:00:00 2001 From: sindoring Date: Thu, 16 Jul 2026 00:51:52 +0400 Subject: [PATCH] fix(M03): support cold rendered ground sample startup --- RENDER.md | 2 + docs/modules/world-renderer.md | 3 ++ src/render/terrain/rendered_ground_sample.gd | 10 +++-- src/tools/verify_rendered_ground_sample.gd | 45 +++++++++++++++++++ .../verify_rendered_ground_sample.gd.uid | 1 + 5 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 src/tools/verify_rendered_ground_sample.gd create mode 100644 src/tools/verify_rendered_ground_sample.gd.uid diff --git a/RENDER.md b/RENDER.md index e30142a..da148c1 100644 --- a/RENDER.md +++ b/RENDER.md @@ -937,6 +937,8 @@ $exe = Join-Path $env:TEMP 'godot-4.6.1-openwc\Godot_v4.6.1-stable_win64.exe' - `WorldRenderFacade.sample_ground_height()` accepts `GodotWorldPosition` and returns renderer-owned immutable `RenderedGroundSample` from already loaded quality/tile-LOD render meshes, avoiding a render-to-gameplay dependency. +- Its factories load the predeclared Script path instead of relying on a warm + global-class cache; a dedicated cold-start verifier covers this bootstrap path. - `renderer_ground_query_snapshot()` preserves the terrain probe's tile readiness, queue position, mesh bounds and nearby seam-fallback diagnostics as a detached Dictionary; callers receive no queue, tile-state, Mesh or Node reference. diff --git a/docs/modules/world-renderer.md b/docs/modules/world-renderer.md index 88c13d7..d35977e 100644 --- a/docs/modules/world-renderer.md +++ b/docs/modules/world-renderer.md @@ -293,6 +293,8 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m gameplay or EditorPlugin package code. - Ground-query facade contract: available/unavailable typed result delegation, detached nested diagnostics and terrain-probe source migration without private access. +- Rendered-ground value contract: available/non-finite/unavailable invariants pass + from a cold Godot class cache before editor import. - Integration/E2E: Eastern Kingdoms/Kalimdor streaming scenes, seven M00 cold/warm checkpoints and one dedicated mapped server-spawn checkpoint. - Fidelity evidence: семь локальных build 12340 reference JPG покрывают terrain/ADT/M2/WMO/liquid/sky и реальный `GryphonRoost01`; automated cold/warm metrics имеют `compared=14`, `missing=0`. Sky использует приблизительно paired camera, а animated-M2 остаётся asset-paired/placement-unpaired из-за synthetic probe. @@ -361,6 +363,7 @@ Exact exported settings and cache versions remain documented in [`../../RENDER.m | `src/domain/streaming/streaming_focus.gd` | Immutable camera-independent streaming position contract | | `src/tools/verify_streaming_focus.gd` | Headless contract, dependency and runtime/tool wiring regression | | `src/tools/verify_world_render_facade.gd` | Focus/metrics/ground delegation, snapshot isolation and consumer wiring regression | +| `src/tools/verify_rendered_ground_sample.gd` | Cold-start renderer ground result invariant regression | | `src/tools/verify_streaming_target_planner.gd` | Planner behavior, dependency and bounded timing regression | | `src/tools/verify_render_budget_scheduler.gd` | Scheduler bounds, shared-lane priority, cancellation and timing regression | | `src/tools/verify_renderer_internal_access.gd` | Gameplay/EditorPlugin/registered renderer-tool boundary gate derived from private streamer fields | diff --git a/src/render/terrain/rendered_ground_sample.gd b/src/render/terrain/rendered_ground_sample.gd index 73fd409..6bcd355 100644 --- a/src/render/terrain/rendered_ground_sample.gd +++ b/src/render/terrain/rendered_ground_sample.gd @@ -20,15 +20,17 @@ var _is_available: bool var _height_units: float var _failure_code: StringName +const SCRIPT_PATH := "res://src/render/terrain/rendered_ground_sample.gd" + ## Creates an available finite rendered-ground sample in Godot world units. -static func available(height_units_value: float) -> RenderedGroundSample: - return RenderedGroundSample.new(true, height_units_value, &"") +static func available(height_units_value: float) -> RefCounted: + return load(SCRIPT_PATH).new(true, height_units_value, &"") ## Creates an unavailable rendered-ground sample with a stable failure code. -static func unavailable(failure_code_value: StringName) -> RenderedGroundSample: - return RenderedGroundSample.new(false, 0.0, failure_code_value) +static func unavailable(failure_code_value: StringName) -> RefCounted: + return load(SCRIPT_PATH).new(false, 0.0, failure_code_value) func _init( diff --git a/src/tools/verify_rendered_ground_sample.gd b/src/tools/verify_rendered_ground_sample.gd new file mode 100644 index 0000000..fa058dc --- /dev/null +++ b/src/tools/verify_rendered_ground_sample.gd @@ -0,0 +1,45 @@ +extends SceneTree + +## Cold-start contract for the renderer-owned ground query result value. + +const SAMPLE_SCRIPT := preload("res://src/render/terrain/rendered_ground_sample.gd") + + +func _initialize() -> void: + var failures: Array[String] = [] + var available_sample: RefCounted = SAMPLE_SCRIPT.available(42.25) + _expect_true(bool(available_sample.get("is_available")), "available sample", failures) + _expect_near(float(available_sample.get("height_units")), 42.25, "available height", failures) + + var non_finite_sample: RefCounted = SAMPLE_SCRIPT.available(INF) + _expect_true(not bool(non_finite_sample.get("is_available")), "non-finite unavailable", failures) + _expect_true( + StringName(non_finite_sample.get("failure_code")) == &"render_terrain_height_not_finite", + "non-finite failure code", + failures + ) + + var unavailable_sample: RefCounted = SAMPLE_SCRIPT.unavailable(&"") + _expect_true( + StringName(unavailable_sample.get("failure_code")) == &"render_terrain_unavailable", + "empty failure code normalization", + failures + ) + + if not failures.is_empty(): + for failure in failures: + push_error("RENDERED_GROUND_SAMPLE: %s" % failure) + quit(1) + return + print("RENDERED_GROUND_SAMPLE PASS contract=3") + 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) diff --git a/src/tools/verify_rendered_ground_sample.gd.uid b/src/tools/verify_rendered_ground_sample.gd.uid new file mode 100644 index 0000000..4e1cd19 --- /dev/null +++ b/src/tools/verify_rendered_ground_sample.gd.uid @@ -0,0 +1 @@ +uid://b8juyikyvx1xw