feat(M03): add environment snapshot facade

This commit is contained in:
2026-07-16 01:00:19 +04:00
parent 60f1e363c0
commit 2ee647a220
12 changed files with 270 additions and 18 deletions
+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 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 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] = [
"res://src/scenes/streaming/eastern_kingdoms_streaming.tscn",
@@ -47,9 +49,18 @@ class StreamingWorldLoaderDouble extends Node:
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:
var failures: Array[String] = []
_verify_rendered_ground_sample_contract(failures)
_verify_sky_controller_application(failures)
await _verify_delegation_and_snapshot_isolation(failures)
_verify_repository_wiring(failures)
@@ -59,7 +70,7 @@ func _initialize() -> void:
quit(1)
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)
@@ -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:
var test_root := Node.new()
var loader := StreamingWorldLoaderDouble.new()
@@ -86,12 +114,16 @@ func _verify_delegation_and_snapshot_isolation(failures: Array[String]) -> void:
var source := Node3D.new()
source.name = "FocusSource"
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()
facade.name = "WorldRenderFacade"
facade.streaming_world_loader_path = NodePath("../StreamingWorldLoaderDouble")
facade.streaming_focus_source_path = NodePath("../FocusSource")
facade.world_environment_controller_path = NodePath("../WorldEnvironmentControllerDouble")
test_root.add_child(loader)
test_root.add_child(source)
test_root.add_child(environment_controller)
test_root.add_child(facade)
get_root().add_child(test_root)
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
_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)
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()
@@ -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('[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('world_environment_controller_path = NodePath("../WowSkyController")'), "%s facade uses sky controller" % scene_path, failures)
for tool_path in TOOL_PATHS:
var tool_source := _read_text(tool_path, failures)
@@ -171,6 +222,24 @@ func _verify_repository_wiring(failures: Array[String]) -> void:
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)
for required_loader_text in [
"func sample_rendered_ground_height(godot_world_position: GodotWorldPosition)",