Files
security-game/src/test/tests/test_materials.gd
T
zwitschi 28f2a48811
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Successful in 5m20s
Add the optional Forward+ desktop HQ build
Package a Forward+ preset with volumetric fog, SDFGI and a volumetric flashlight
for a separate Linux/Windows Desktop HQ zip. Gate the effects on a real
RenderingDevice, tune LATE fog, and adapt local light falloff for Godot 4.7.
Record the Compatibility/Forward+ A/B captures and metrics, add the artifact to
the build/publish scripts, and keep the default Compatibility/Web path
unchanged. Headless 231/231, Python 87/87; exported HQ binary boots with Vulkan.
2026-11-01 19:40:42 +01:00

103 lines
5.1 KiB
GDScript

extends RefCounted
## Headless tests for the shared surface/environment recipes (ADR-0012).
const Materials := preload("res://src/game/materials.gd")
const GameManager := preload("res://src/game/game_manager.gd")
const Rules := preload("res://src/core/rules.gd")
func test_every_profile_has_physical_values() -> bool:
var ok := true
for role in ["brick", "concrete", "asphalt", "awning", "stone", "metal",
"painted_metal", "wood", "cloth", "skin", "glass", "rubber"]:
var profile: Dictionary = Materials.profile(role)
var roughness: float = float(profile.get("roughness", -1.0))
var metallic: float = float(profile.get("metallic", -1.0))
if roughness < 0.0 or roughness > 1.0:
ok = false
if metallic < 0.0 or metallic > 1.0:
ok = false
return TestUtils.check(ok, "all roles have roughness/metallic in 0..1")
func test_textured_recipes_keep_their_texture_and_profile() -> bool:
var brick := Materials.brick()
var concrete := Materials.concrete()
var asphalt := Materials.asphalt()
var awning := Materials.awning()
var a := TestUtils.check(brick.albedo_texture != null, "brick keeps its texture")
var b := TestUtils.check(concrete.uv1_scale.x > 1.0, "concrete tiles across the sidewalk")
var c := TestUtils.check(asphalt.roughness < brick.roughness, "asphalt is smoother than brick")
var d := TestUtils.check(awning.albedo_texture != null, "awning keeps its texture")
var e := TestUtils.check(Materials.flat(Color.RED, "metal").metallic > 0.5, "metal role is metallic")
return a and b and c and d and e
func test_realism_pick_tiles_and_wet_asphalt() -> bool:
## The realism pass swapped the flat first-generation tiles for the v2 picks.
## The street has a dry and a wet variant for day and late night.
var brick := Materials.brick()
var dry := Materials.asphalt()
var wet := Materials.asphalt(Color(0.46, 0.48, 0.53), Vector2(30, 7), true)
var a := TestUtils.check(brick.albedo_texture.resource_path.contains("v2/picks/"),
"brick uses the promoted v2 pick")
var b := TestUtils.check(brick.normal_enabled and brick.normal_texture != null,
"brick carries its normal map")
var c := TestUtils.check(dry.albedo_texture != wet.albedo_texture,
"wet asphalt uses its own albedo")
var d := TestUtils.check(wet.roughness < dry.roughness,
"wet asphalt is glossier than dry asphalt")
var e := TestUtils.check(wet.metallic_specular > dry.metallic_specular,
"wet asphalt catches the lamps")
var f := TestUtils.check(wet.albedo_texture.resource_path.contains("picks"),
"the wet map is a promoted pick")
return a and b and c and d and e and f
func test_glass_and_emissive_recipes() -> bool:
var glass := Materials.glass()
var pane := Materials.window_pane()
var bar := Materials.emissive(Color(1.0, 0.35, 0.75), 2.5)
var a := TestUtils.check(glass.transparency == BaseMaterial3D.TRANSPARENCY_ALPHA,
"glass is alpha blended")
var b := TestUtils.check(glass.roughness < 0.2, "glass is smooth")
var c := TestUtils.check(pane.emission_enabled, "window panes can light up")
var d := TestUtils.check(is_equal_approx(pane.emission_energy_multiplier, 0.0),
"window panes start dark")
var e := TestUtils.check(is_equal_approx(bar.emission_energy_multiplier, 2.5),
"emissive energy is applied")
return a and b and c and d and e
func test_environment_tuning_applies_phase_values() -> bool:
var env := Environment.new()
var late: Dictionary = GameManager.PHASE_LIGHTING[Rules.Phase.LATE]
Materials.configure_environment(env, late)
var a := TestUtils.check(env.tonemap_mode == Environment.TONE_MAPPER_ACES,
"ACES tonemapping")
var b := TestUtils.check(env.glow_enabled, "glow enabled for the marquee")
var c := TestUtils.check(env.fog_enabled, "fog enabled for distance haze")
var d := TestUtils.check(env.fog_density > 0.0, "fog has a density")
var e := TestUtils.check(env.adjustment_enabled, "colour grading enabled")
var f := TestUtils.check(
env.fog_light_color.is_equal_approx(late["fog_color"]),
"phase fog colour is used")
var advanced := Materials.forward_plus_active()
var g := TestUtils.check(env.volumetric_fog_enabled == advanced,
"volumetric fog is gated to Forward+ (advanced=%s)" % advanced)
var h := TestUtils.check(env.sdfgi_enabled == advanced,
"SDFGI is gated to Forward+ (advanced=%s)" % advanced)
return a and b and c and d and e and f and g and h
func test_every_phase_has_environment_keys() -> bool:
var ok := true
for phase in [Rules.Phase.EARLY, Rules.Phase.MIDDAY, Rules.Phase.EVENING, Rules.Phase.LATE]:
var cfg: Dictionary = GameManager.PHASE_LIGHTING.get(phase, {})
for key in ["exposure", "glow", "fog_color", "fog_density", "fog_energy",
"contrast", "saturation", "volumetric_density", "volumetric_energy"]:
if not cfg.has(key):
ok = false
return TestUtils.check(ok, "all phases set exposure/glow/fog/grading")
func test_night_phases_are_night() -> bool:
var evening: Dictionary = GameManager.PHASE_LIGHTING[Rules.Phase.EVENING]
var late: Dictionary = GameManager.PHASE_LIGHTING[Rules.Phase.LATE]
var early: Dictionary = GameManager.PHASE_LIGHTING[Rules.Phase.EARLY]
return TestUtils.check(bool(evening["night"]) and bool(late["night"]) and not bool(early["night"]),
"night flag matches the phase")