extends SceneTree ## Checks the sunlit shallows visual site keeps its three promises: ## a flat floor, a calm shadow-only water surface, and a daytime sun whose ## hour never changes. const SCENE_PATH := "res://game/world/sites/sunlit_shallows_environment.tscn" const WORLD_SCENE_PATH := ( "res://game/composition/vertical_slice/sunlit_shallows_world.tscn" ) var _failures: Array[String] = [] var _checks := 0 func _init() -> void: _run.call_deferred() func _run() -> void: var scene := load(SCENE_PATH) as PackedScene _expect(scene != null, "scene loads") if scene == null: _finish() return var site := scene.instantiate() as SunlitShallowsEnvironment _expect(site != null, "scene root is SunlitShallowsEnvironment") if site == null: _finish() return root.add_child(site) await process_frame _test_fixed_daytime_sun(site) _test_flat_floor(site) _test_calm_surface_occluder(site) _test_scattering_environment(site) _test_air_fog_cut(site) _test_surface_ceiling(site) site.queue_free() await process_frame _test_composed_world() _finish() func _test_composed_world() -> void: var world_scene := load(WORLD_SCENE_PATH) as PackedScene _expect(world_scene != null, "composed world scene loads") if world_scene == null: return var world := world_scene.instantiate() as Node3D _expect( world.get_node_or_null("Environment") is SunlitShallowsEnvironment, "composed world uses the sunlit shallows environment" ) var submarine := world.get_node_or_null("SubmarineActor") as Node3D _expect(submarine != null, "composed world has a submarine") if submarine != null: _expect( submarine.position.y < SunlitShallowsEnvironment.SURFACE_LEVEL_M and submarine.position.y > SunlitShallowsEnvironment.FLOOR_DEPTH_M, "submarine starts between surface and floor" ) _expect( submarine.get_node_or_null("CockpitInterior") != null and submarine.get_node_or_null("CockpitCameraRig") != null, "submarine carries cockpit and camera rig" ) for projector_name: String in ["LeftProjector", "RightProjector"]: var projector := submarine.get_node_or_null(projector_name) as SpotLight3D _expect(projector != null, "%s exists" % projector_name) if projector != null: _expect( projector.light_volumetric_fog_energy < 1.0, "%s does not wash out the sun shafts in the fog" % projector_name ) world.free() func _test_fixed_daytime_sun(site: SunlitShallowsEnvironment) -> void: var sun := site.get_node_or_null("Sun") as DirectionalLight3D _expect(sun != null, "sun is a DirectionalLight3D") if sun == null: return _expect( sun.rotation_degrees.is_equal_approx( SunlitShallowsEnvironment.SUN_ROTATION_DEGREES ), "sun hour is the fixed constant" ) var sun_direction := -sun.global_transform.basis.z _expect(sun_direction.y < -0.6, "sun shines downward from above the porthole (daytime)") _expect( sun_direction.z > 0.15, "sun shines toward the observer (rays come from ahead, world -Z)" ) _expect(sun.shadow_enabled, "sun casts shadows (needed for light shafts)") _expect( sun.light_volumetric_fog_energy >= 1.0, "sun injects energy into the volumetric fog" ) func _test_flat_floor(site: SunlitShallowsEnvironment) -> void: var floor_mesh := site.get_node_or_null("FlatFloor/Mesh") as MeshInstance3D _expect(floor_mesh != null, "floor mesh exists") if floor_mesh == null: return var vertices := floor_mesh.mesh.get_faces() var flat := true for vertex: Vector3 in vertices: if not is_zero_approx(vertex.y): flat = false break _expect(flat, "floor mesh is flat") _expect( is_equal_approx( floor_mesh.global_position.y, SunlitShallowsEnvironment.FLOOR_DEPTH_M ), "floor sits at the site depth" ) _expect( floor_mesh.material_override is ShaderMaterial, "floor uses the caustic shader material" ) var collision := site.get_node_or_null("FlatFloor/Collision") as CollisionShape3D _expect(collision != null and collision.shape is BoxShape3D, "floor has a box collider") func _test_calm_surface_occluder(site: SunlitShallowsEnvironment) -> void: var occluder := site.get_node_or_null("CalmSurfaceOccluder") as MeshInstance3D _expect(occluder != null, "surface occluder exists") if occluder == null: return _expect( occluder.cast_shadow == GeometryInstance3D.SHADOW_CASTING_SETTING_SHADOWS_ONLY, "surface occluder is shadow-only" ) _expect( is_equal_approx( occluder.global_position.y, SunlitShallowsEnvironment.SURFACE_LEVEL_M ), "surface occluder sits at water level" ) var material := occluder.material_override as ShaderMaterial _expect(material != null, "surface occluder uses a shader material") if material == null: return var drift: Variant = material.get_shader_parameter("drift_speed") _expect( drift is float and drift > 0.0 and drift < 0.05, "surface drift is slow (calm water)" ) _expect( material.get_shader_parameter("ripple_noise") is NoiseTexture2D, "surface ripple noise is assigned" ) var pool_center: Variant = material.get_shader_parameter("pool_center_xz") _expect( pool_center is Vector2 and pool_center.y < -20.0 and pool_center.y > -120.0, "light pool sits a few tens of metres ahead (world -Z)" ) var pool_radius: Variant = material.get_shader_parameter("pool_radius") _expect( pool_radius is float and pool_radius > 5.0 and pool_radius < 60.0, "light pool radius is local, not the whole surface" ) func _test_scattering_environment(site: SunlitShallowsEnvironment) -> void: var world_environment := site.get_node_or_null("WorldEnvironment") as WorldEnvironment _expect(world_environment != null, "world environment exists") if world_environment == null: return var environment := world_environment.environment _expect(environment.volumetric_fog_enabled, "volumetric fog is enabled") _expect(environment.volumetric_fog_anisotropy > 0.5, "fog scatters forward") _expect(environment.fog_enabled, "depth fog is enabled") func _test_surface_ceiling(site: SunlitShallowsEnvironment) -> void: var ceiling := site.get_node_or_null("SurfaceCeiling") as MeshInstance3D _expect(ceiling != null, "visible surface ceiling exists") if ceiling == null: return _expect( is_equal_approx(ceiling.global_position.y, SunlitShallowsEnvironment.SURFACE_LEVEL_M), "surface ceiling sits at water level" ) _expect( ceiling.cast_shadow == GeometryInstance3D.SHADOW_CASTING_SETTING_OFF, "surface ceiling leaves shadowing to the occluder" ) var ceiling_material := ceiling.material_override as ShaderMaterial var occluder := site.get_node_or_null("CalmSurfaceOccluder") as MeshInstance3D var occluder_material: ShaderMaterial = null if occluder == null else occluder.material_override _expect( ceiling_material != null and occluder_material != null and ceiling_material.get_shader_parameter("pool_center_xz") == occluder_material.get_shader_parameter("pool_center_xz") and ceiling_material.get_shader_parameter("pool_radius") == occluder_material.get_shader_parameter("pool_radius"), "surface ceiling lights the same pool the occluder opens" ) func _test_air_fog_cut(site: SunlitShallowsEnvironment) -> void: var air := site.get_node_or_null("AirFogCut") as FogVolume _expect(air != null, "air fog cut exists") if air == null: return var bottom := air.global_position.y - air.size.y * 0.5 _expect( is_equal_approx(bottom, SunlitShallowsEnvironment.SURFACE_LEVEL_M), "air fog cut starts at the water surface" ) var material := air.material as FogMaterial _expect(material != null and material.density < 0.0, "air fog cut subtracts fog") var world_environment := site.get_node("WorldEnvironment") as WorldEnvironment _expect( material != null and is_equal_approx( -material.density, world_environment.environment.volumetric_fog_density ), "air fog cut cancels the global volumetric density exactly" ) func _expect(condition: bool, label: String) -> void: _checks += 1 if not condition: _failures.append(label) func _finish() -> void: if _failures.is_empty(): print("Sunlit shallows environment: %d passed, 0 failed." % _checks) quit(0) else: for failure: String in _failures: push_error("sunlit shallows environment: %s" % failure) print("Sunlit shallows environment: %d failed." % _failures.size()) quit(1)