straywild/tests/terrain_seasonal_material_validation.gd

274 lines
7.6 KiB
GDScript

extends SceneTree
const CalendarSeasonType = preload("res://world/calendar_season.gd")
const PropCatalog: TerrainPropCatalog = preload(
"res://world/generation/props/terrain_prop_catalog.tres"
)
const RegionScene: PackedScene = preload(
"res://world/generation/generated_world_region.tscn"
)
const BROADLEAF_IDS: Array[StringName] = [
&"prop_tree_1",
&"prop_tree_2",
&"prop_tree_3",
&"prop_tree_large",
]
const IMPORTED_FOLIAGE_NAMES: Dictionary = {
&"prop_tree_1": &"leaf_autumn_light",
&"prop_tree_2": &"leaf_autumn",
&"prop_tree_3": &"leaf_autumn_dark",
&"prop_tree_large": &"leaf_autumn_mid",
&"prop_pine": &"pine_summer",
&"prop_pine_large": &"pine_autumn",
&"prop_palm": &"palm_autumn",
}
const PROP_PRIMARY_MATERIAL_ROLL_META: StringName = (
&"terrain_prop_primary_material_roll"
)
const PROP_LEGACY_PRIMARY_MATERIAL_INDEX_META: StringName = (
&"terrain_prop_legacy_primary_material_index"
)
func _initialize() -> void:
call_deferred(&"_run")
func _run() -> void:
assert(PropCatalog.validation_errors().is_empty())
for stable_id: StringName in BROADLEAF_IDS:
var definition := PropCatalog.definition_for_id(stable_id)
assert(definition != null)
_assert_palette(
definition.summer_material_variants,
PackedStringArray([
"leaf_variant_light",
"leaf_variant_mid",
"leaf_variant_dark",
]),
[
Color(0.3387566, 0.7186728, 0, 1),
Color(0.3146831, 0.4631305, 0, 1),
Color(0.1712407, 0.2520192, 0, 1),
],
)
_assert_palette(
definition.fall_material_variants,
PackedStringArray([
"leaf_autumn_light",
"leaf_autumn",
"leaf_autumn_mid",
"leaf_autumn_dark",
]),
[
Color(0.8222013, 0.794216, 0, 1),
Color(0.6186816, 0.4523746, 0, 1),
Color(0.6841143, 0.3515543, 0, 1),
Color(0.3853541, 0.00134692, 0, 1),
],
)
assert(
definition.primary_material_variants_for_season(
CalendarSeasonType.Season.SPRING
) == definition.summer_material_variants
)
assert(
definition.primary_material_variants_for_season(
CalendarSeasonType.Season.WINTER
) == definition.summer_material_variants
)
_assert_single_seasonal_tree(
&"prop_pine",
&"pine_summer",
Color(0.02171588, 0.2242201, 0.1360403, 1),
&"pine_autumn",
Color(0.02388079, 0.1285609, 0, 1),
)
_assert_single_seasonal_tree(
&"prop_pine_large",
&"pine_summer",
Color(0.02171588, 0.2242201, 0.1360403, 1),
&"pine_autumn",
Color(0.02388079, 0.1285609, 0, 1),
)
_assert_single_seasonal_tree(
&"prop_palm",
&"palm_summer",
Color(0.3146831, 0.4631305, 0, 1),
&"palm_autumn",
Color(0.2951757, 0.3575695, 0.162893, 1),
)
for stable_id: StringName in IMPORTED_FOLIAGE_NAMES:
var definition := PropCatalog.definition_for_id(stable_id)
var instance := definition.packed_scene.instantiate()
var material_names := PackedStringArray()
_collect_material_names(instance, material_names)
assert(IMPORTED_FOLIAGE_NAMES[stable_id] in material_names)
instance.free()
var region := RegionScene.instantiate() as GeneratedWorldRegion
assert(region != null)
assert(bool(region.call(
"_material_name_matches_targets",
&"leaf_autumn_mid",
PackedStringArray(["leaf"]),
)))
assert(bool(region.call(
"_material_name_matches_targets",
&"pine_winter",
PackedStringArray(["pine"]),
)))
assert(bool(region.call(
"_material_name_matches_targets",
&"palm_spring",
PackedStringArray(["palm"]),
)))
_validate_palette_roll_mapping(region)
_validate_primary_roll_random_state(region)
region.free()
print("Terrain seasonal material validation: PASS")
quit()
func _assert_single_seasonal_tree(
stable_id: StringName,
summer_name: StringName,
summer_color: Color,
fall_name: StringName,
fall_color: Color,
) -> void:
var definition := PropCatalog.definition_for_id(stable_id)
assert(definition != null)
_assert_palette(
definition.summer_material_variants,
PackedStringArray([summer_name]),
[summer_color],
)
_assert_palette(
definition.fall_material_variants,
PackedStringArray([fall_name]),
[fall_color],
)
func _assert_palette(
materials: Array[Material],
expected_names: PackedStringArray,
expected_colors: Array[Color],
) -> void:
assert(materials.size() == expected_names.size())
assert(materials.size() == expected_colors.size())
for index: int in materials.size():
var material := materials[index] as StandardMaterial3D
assert(material != null)
assert(material.resource_name == expected_names[index])
assert(material.albedo_color.is_equal_approx(expected_colors[index]))
func _validate_palette_roll_mapping(region: GeneratedWorldRegion) -> void:
var definition := PropCatalog.definition_for_id(&"prop_tree_1")
assert(definition != null)
var instance := definition.packed_scene.instantiate()
var palette := definition.fall_material_variants
for index: int in palette.size():
var roll := (float(index) + 0.5) / float(palette.size())
region.call(
"_apply_material_variant_for_roll",
instance,
definition.variant_material_slot_names,
palette,
roll,
)
assert(_has_surface_override(instance, palette[index]))
instance.free()
func _validate_primary_roll_random_state(
region: GeneratedWorldRegion,
) -> void:
var broadleaf := PropCatalog.definition_for_id(&"prop_tree_1")
var baseline := RandomNumberGenerator.new()
baseline.seed = 29092026
var actual := RandomNumberGenerator.new()
actual.seed = baseline.seed
var legacy_index := baseline.randi_range(
0,
broadleaf.material_variants.size() - 1,
)
var selection := region.call(
"_primary_material_selection",
broadleaf,
actual,
) as Dictionary
var roll := float(selection.get("roll", -1.0))
assert(roll >= 0.0 and roll < 1.0)
assert(int(selection.get("legacy_index", -1)) == legacy_index)
assert(actual.state == baseline.state)
var prop := Node3D.new()
prop.set_meta(PROP_PRIMARY_MATERIAL_ROLL_META, 0.125)
prop.set_meta(
PROP_LEGACY_PRIMARY_MATERIAL_INDEX_META,
legacy_index,
)
var summer_roll := float(region.call(
"_primary_material_roll_for_palette",
prop,
broadleaf,
broadleaf.summer_material_variants,
))
assert(
floori(summer_roll * broadleaf.summer_material_variants.size())
== legacy_index
)
var fall_roll := float(region.call(
"_primary_material_roll_for_palette",
prop,
broadleaf,
broadleaf.fall_material_variants,
))
assert(is_equal_approx(fall_roll, 0.125))
prop.free()
var pine := PropCatalog.definition_for_id(&"prop_pine")
var pine_random := RandomNumberGenerator.new()
pine_random.seed = 29092026
var pine_initial_state := pine_random.state
var pine_selection := region.call(
"_primary_material_selection",
pine,
pine_random,
) as Dictionary
assert(int(pine_selection.get("legacy_index", -2)) == -1)
assert(pine_random.state == pine_initial_state)
func _has_surface_override(root_node: Node, expected: Material) -> bool:
var mesh_instance := root_node as MeshInstance3D
if mesh_instance != null and mesh_instance.mesh != null:
for surface_index: int in mesh_instance.mesh.get_surface_count():
if (
mesh_instance.get_surface_override_material(surface_index)
== expected
):
return true
for child: Node in root_node.get_children():
if _has_surface_override(child, expected):
return true
return false
func _collect_material_names(
node: Node,
material_names: PackedStringArray,
) -> void:
var mesh_instance := node as MeshInstance3D
if mesh_instance != null and mesh_instance.mesh != null:
for surface_index: int in mesh_instance.mesh.get_surface_count():
var material := mesh_instance.mesh.surface_get_material(surface_index)
if material != null:
material_names.append(material.resource_name)
for child: Node in node.get_children():
_collect_material_names(child, material_names)