feat(tools): modifier phase and per-primitive material hook in the site baker
The bake order is now primitive sum, modifiers (with the local gradient), floor clamp, slope material, primitive materials, material patches. A regression test checks the Banc du Vigilant still bakes byte for byte. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
9454b9e552
commit
520a62863b
2 files changed
+118
-3
No files matched your search
@@ -3,8 +3,12 @@ extends SceneTree
|
||||
const SonarMaterial = preload("res://game/domain/sonar/sonar_material.gd")
|
||||
const SiteTerrainBaker = preload("res://tools/site_terrain_baker.gd")
|
||||
const VehicleTestRecipe = preload("res://tools/sites/vehicle_test_terrain_recipe.gd")
|
||||
const Zone1Recipe = preload("res://tools/sites/zone1_vigilant_recipe.gd")
|
||||
const SiteTerrainData = preload("res://game/domain/sites/site_terrain_data.gd")
|
||||
|
||||
const TEST_COUNT := 10
|
||||
const ZONE1_TERRAIN_PATH := "res://content/sites/zone1_vigilant_terrain.res"
|
||||
|
||||
const TEST_COUNT := 16
|
||||
|
||||
var _failures: Array[String] = []
|
||||
|
||||
@@ -12,6 +16,8 @@ var _failures: Array[String] = []
|
||||
func _init() -> void:
|
||||
_test_plane_and_blob()
|
||||
_test_materials_and_determinism()
|
||||
_test_modifiers_and_primitive_materials()
|
||||
_test_zone1_artefact_is_stable()
|
||||
|
||||
if _failures.is_empty():
|
||||
print("Site baker unit tests: %d passed, 0 failed." % TEST_COUNT)
|
||||
@@ -66,6 +72,59 @@ func _test_materials_and_determinism() -> void:
|
||||
_expect(calibration != null and calibration.validation_error().is_empty(), "calibration recipe bakes valid data")
|
||||
|
||||
|
||||
## Test doubles for the extension points: a modifier that lifts the field by one metre
|
||||
## and a primitive that forces rock on a flat plane.
|
||||
class Lift extends SiteTerrainBaker.Modifier:
|
||||
func modify(_x_m: float, _z_m: float, elevation_m: float, _gradient: Vector2) -> float:
|
||||
return elevation_m + 1.0
|
||||
|
||||
|
||||
class GradientProbe extends SiteTerrainBaker.Modifier:
|
||||
var gradient_at_centre := Vector2.ZERO
|
||||
|
||||
func modify(x_m: float, z_m: float, elevation_m: float, gradient: Vector2) -> float:
|
||||
if is_zero_approx(x_m) and is_zero_approx(z_m):
|
||||
gradient_at_centre = gradient
|
||||
return elevation_m
|
||||
|
||||
|
||||
class RockDisc extends SiteTerrainBaker.Primitive:
|
||||
func material_at(x_m: float, z_m: float) -> int:
|
||||
if Vector2(x_m, z_m).length() <= 5.0:
|
||||
return SonarMaterial.Value.ROCK
|
||||
return SiteTerrainBaker.NO_MATERIAL
|
||||
|
||||
|
||||
func _test_modifiers_and_primitive_materials() -> void:
|
||||
var recipe := _small_recipe()
|
||||
recipe.primitives.append(SiteTerrainBaker.SlopedPlane.new(30.0, 0.2, 0.0, 0.0, 0.0))
|
||||
var probe := GradientProbe.new()
|
||||
recipe.modifiers.append(probe)
|
||||
recipe.modifiers.append(Lift.new())
|
||||
var data := SiteTerrainBaker.bake(recipe)
|
||||
_expect(is_equal_approx(data.elevations_m[data.index_of(10, 10)], -29.0), "modifier runs after the primitive sum")
|
||||
_expect(probe.gradient_at_centre.is_equal_approx(Vector2(0.2, 0.0)), "modifier receives the local gradient (%s)" % probe.gradient_at_centre)
|
||||
|
||||
var flat := _small_recipe()
|
||||
flat.primitives.append(SiteTerrainBaker.SlopedPlane.new(30.0, 0.0, 0.0, 0.0, 0.0))
|
||||
flat.primitives.append(RockDisc.new())
|
||||
var flat_data := SiteTerrainBaker.bake(flat)
|
||||
_expect(flat_data.materials[flat_data.index_of(10, 10)] == SonarMaterial.Value.ROCK, "primitive material wins over the slope rule")
|
||||
_expect(flat_data.materials[flat_data.index_of(0, 0)] == SonarMaterial.Value.SAND, "primitive material is local")
|
||||
|
||||
|
||||
func _test_zone1_artefact_is_stable() -> void:
|
||||
var versioned := load(ZONE1_TERRAIN_PATH) as SiteTerrainData
|
||||
_expect(versioned != null, "versioned zone 1 terrain loads")
|
||||
if versioned == null:
|
||||
return
|
||||
var baked := SiteTerrainBaker.bake(Zone1Recipe.recipe())
|
||||
_expect(
|
||||
baked.elevations_m == versioned.elevations_m and baked.materials == versioned.materials,
|
||||
"zone 1 recipe still bakes the versioned artefact byte for byte"
|
||||
)
|
||||
|
||||
|
||||
func _expect(condition: bool, label: String) -> void:
|
||||
if not condition:
|
||||
_failures.append(label)
|
||||
Reference in new issue
Block a user