forked from woofmeow/straywild
Add layered inland cliff generation
This commit is contained in:
parent
2710544070
commit
86372a652e
66 changed files with 1552 additions and 79 deletions
|
|
@ -82,8 +82,14 @@ func _validate_generated_region(
|
|||
generator: TerrainChunkGenerator,
|
||||
) -> void:
|
||||
var placements := generator.placement_keys()
|
||||
assert(placements.size() == 49)
|
||||
assert(placements[24].begins_with("chunk_spawn@"))
|
||||
var expected_chunk_count := generator.grid_size.x * generator.grid_size.y
|
||||
var center := Vector2i(
|
||||
generator.grid_size.x / 2,
|
||||
generator.grid_size.y / 2,
|
||||
)
|
||||
var center_index := center.y * generator.grid_size.x + center.x
|
||||
assert(placements.size() == expected_chunk_count)
|
||||
assert(placements[center_index].begins_with("chunk_spawn@"))
|
||||
assert(_placement_count(placements, "chunk_spawn") == 1)
|
||||
assert(_placement_count(placements, "chunk_0001") >= 1)
|
||||
assert(_placement_count(placements, "chunk_0002") >= 1)
|
||||
|
|
@ -92,8 +98,24 @@ func _validate_generated_region(
|
|||
assert(_placement_count(placements, "chunk_0005") >= 1)
|
||||
assert(_placement_count(placements, "chunk_0006") >= 1)
|
||||
assert(_placement_count(placements, "chunk_0007") >= 1)
|
||||
assert(generator.get_generated_chunks_root().get_child_count() == 49)
|
||||
assert(generator.get_primary_terrain_meshes().size() == 49)
|
||||
assert(_placement_count(placements, "chunk_0008") >= 1)
|
||||
assert(_placement_count(placements, "chunk_0009") == 1)
|
||||
assert(_placement_count(placements, "chunk_0010") == 4)
|
||||
assert(
|
||||
_placement_count(placements, "chunk_0011")
|
||||
+ _placement_count(placements, "chunk_0012")
|
||||
== 4
|
||||
)
|
||||
assert(_placement_count(placements, "chunk_0012") <= 1)
|
||||
assert(
|
||||
generator.get_generated_chunks_root().get_child_count()
|
||||
== expected_chunk_count
|
||||
)
|
||||
assert(
|
||||
generator.get_primary_terrain_meshes().size()
|
||||
== expected_chunk_count
|
||||
)
|
||||
_validate_elevated_cliff_feature(generator)
|
||||
|
||||
var shop := region.get_node("Interactables/FishingShopWorld") as Node3D
|
||||
var storage := region.get_node("Interactables/PlayerStorageBox") as Node3D
|
||||
|
|
@ -111,6 +133,7 @@ func _validate_generated_region(
|
|||
var fresh_root := region.get_node("WaterBodies/FreshWaterBodies") as Node3D
|
||||
assert(ocean != null and fresh_root != null)
|
||||
assert(ocean.water_type == WaterType.Type.SALT_WATER)
|
||||
assert(is_equal_approx(ocean.position.y, GeneratedWorldRegion.WATER_HEIGHT))
|
||||
var fresh_placement_count := 0
|
||||
for record: Dictionary in generator.placement_records():
|
||||
var tags: PackedStringArray = record.get("tags", PackedStringArray())
|
||||
|
|
@ -123,6 +146,7 @@ func _validate_generated_region(
|
|||
var fresh := child as WaterBodyAuthoring
|
||||
assert(fresh != null)
|
||||
assert(fresh.water_type == WaterType.Type.FRESH_WATER)
|
||||
assert(is_equal_approx(fresh.position.y, GeneratedWorldRegion.WATER_HEIGHT))
|
||||
assert(fresh.visible)
|
||||
assert(fresh.surface_size.x < 10.0 or fresh.surface_size.y < 10.0)
|
||||
assert(not fresh.visual_surface_enabled)
|
||||
|
|
@ -155,13 +179,13 @@ func _validate_generated_region(
|
|||
&"terrain_chunk_coordinate",
|
||||
Vector2i.ZERO,
|
||||
)
|
||||
var center := Vector2i(
|
||||
var spawn_coordinate := Vector2i(
|
||||
generator.grid_size.x / 2,
|
||||
generator.grid_size.y / 2,
|
||||
)
|
||||
var spawn_distance := (
|
||||
absi(coordinate.x - center.x)
|
||||
+ absi(coordinate.y - center.y)
|
||||
absi(coordinate.x - spawn_coordinate.x)
|
||||
+ absi(coordinate.y - spawn_coordinate.y)
|
||||
)
|
||||
assert(spawn_distance >= definition.minimum_spawn_chunk_distance)
|
||||
_validate_decoration_transform(
|
||||
|
|
@ -169,6 +193,13 @@ func _validate_generated_region(
|
|||
child as Node3D,
|
||||
definition,
|
||||
)
|
||||
if prop_id in [&"prop_tree_1", &"prop_tree_2", &"prop_tree_3"]:
|
||||
assert(
|
||||
_has_material_variant_override(
|
||||
child.get_node_or_null("Visual"),
|
||||
definition.material_variants,
|
||||
)
|
||||
)
|
||||
assert(_decoration_group_count(region, &"grass_tree") > 0)
|
||||
assert(_decoration_group_count(region, &"sand_tree") > 0)
|
||||
assert(
|
||||
|
|
@ -187,6 +218,69 @@ func _validate_generated_region(
|
|||
)
|
||||
|
||||
|
||||
func _validate_elevated_cliff_feature(
|
||||
generator: TerrainChunkGenerator,
|
||||
) -> void:
|
||||
var elevated_coordinates: Dictionary[Vector2i, StringName] = {}
|
||||
var top_coordinate := Vector2i(-1, -1)
|
||||
for record: Dictionary in generator.placement_records():
|
||||
var stable_id: StringName = record.get("stable_id", &"")
|
||||
if stable_id not in [
|
||||
&"chunk_0009",
|
||||
&"chunk_0010",
|
||||
&"chunk_0011",
|
||||
&"chunk_0012",
|
||||
]:
|
||||
continue
|
||||
var coordinate: Vector2i = record.get("coordinate", Vector2i.ZERO)
|
||||
assert(coordinate.x > 0 and coordinate.x < generator.grid_size.x - 1)
|
||||
assert(coordinate.y > 0 and coordinate.y < generator.grid_size.y - 1)
|
||||
elevated_coordinates[coordinate] = stable_id
|
||||
if stable_id == &"chunk_0009":
|
||||
top_coordinate = coordinate
|
||||
assert(elevated_coordinates.size() == 9)
|
||||
assert(top_coordinate != Vector2i(-1, -1))
|
||||
for row_offset: int in range(-1, 2):
|
||||
for column_offset: int in range(-1, 2):
|
||||
assert(
|
||||
elevated_coordinates.has(
|
||||
top_coordinate + Vector2i(column_offset, row_offset)
|
||||
)
|
||||
)
|
||||
|
||||
var generated := generator.get_generated_chunks_root()
|
||||
assert(generated != null)
|
||||
var layered_count := 0
|
||||
for chunk_root: Node in generated.get_children():
|
||||
var stable_id := StringName(
|
||||
chunk_root.get_meta(&"terrain_chunk_id", &"")
|
||||
)
|
||||
if stable_id not in [
|
||||
&"chunk_0009",
|
||||
&"chunk_0010",
|
||||
&"chunk_0011",
|
||||
&"chunk_0012",
|
||||
]:
|
||||
continue
|
||||
layered_count += 1
|
||||
var base_layer := chunk_root.get_node_or_null("TerrainBaseLayer")
|
||||
var overlay := chunk_root.get_node_or_null("TerrainOverlay")
|
||||
assert(base_layer != null and overlay != null)
|
||||
var base_mesh := TerrainChunkAnalyzer.find_primary_mesh(
|
||||
base_layer,
|
||||
&"chunk_0000",
|
||||
)
|
||||
var overlay_mesh := TerrainChunkAnalyzer.find_primary_mesh(
|
||||
overlay,
|
||||
stable_id,
|
||||
)
|
||||
assert(base_mesh != null and base_mesh.mesh != null)
|
||||
assert(overlay_mesh != null and overlay_mesh.mesh != null)
|
||||
assert(base_mesh.has_node("TerrainBaseLayerCollision"))
|
||||
assert(overlay_mesh.has_node("TerrainCollision"))
|
||||
assert(layered_count == 9)
|
||||
|
||||
|
||||
func _validate_ocean_facing_record(
|
||||
record: Dictionary,
|
||||
grid_size: Vector2i,
|
||||
|
|
@ -224,6 +318,23 @@ func _validate_prop_catalog(region: GeneratedWorldRegion) -> void:
|
|||
assert(instance.position.is_zero_approx())
|
||||
assert(_find_mesh_instance(instance) != null)
|
||||
instance.free()
|
||||
var mushroom := catalog.definition_for_id(&"prop_mushroom")
|
||||
assert(mushroom != null and mushroom.has_collision())
|
||||
assert(mushroom.visual_offset.y < 0.0)
|
||||
for tree_id: StringName in [
|
||||
&"prop_tree_1",
|
||||
&"prop_tree_2",
|
||||
&"prop_tree_3",
|
||||
]:
|
||||
var tree := catalog.definition_for_id(tree_id)
|
||||
assert(tree != null)
|
||||
assert(tree.minimum_visual_scale < tree.maximum_visual_scale)
|
||||
assert(tree.material_variants.size() >= 3)
|
||||
assert(not tree.variant_material_slot_names.is_empty())
|
||||
var pine := catalog.definition_for_id(&"prop_pine")
|
||||
assert(pine != null)
|
||||
assert(pine.minimum_visual_scale < pine.maximum_visual_scale)
|
||||
assert(pine.material_variants.is_empty())
|
||||
|
||||
|
||||
func _validate_biome_catalog(
|
||||
|
|
@ -276,7 +387,16 @@ func _validate_decoration_transform(
|
|||
var collision := prop.get_node_or_null(
|
||||
"TrunkCollision/CollisionShape"
|
||||
) as CollisionShape3D
|
||||
assert(visual_root != null and visual_root.position.is_zero_approx())
|
||||
assert(visual_root != null)
|
||||
assert(visual_root.position.is_equal_approx(definition.visual_offset))
|
||||
var visual_scale := float(
|
||||
prop.get_meta(&"terrain_prop_visual_scale", 1.0)
|
||||
)
|
||||
assert(visual_scale >= definition.minimum_visual_scale - 0.001)
|
||||
assert(visual_scale <= definition.maximum_visual_scale + 0.001)
|
||||
assert(
|
||||
visual_root.scale.is_equal_approx(Vector3.ONE * visual_scale)
|
||||
)
|
||||
assert(visual != null and visual.mesh != null)
|
||||
if definition.has_collision():
|
||||
assert(collision != null)
|
||||
|
|
@ -319,6 +439,26 @@ func _find_mesh_instance(root_node: Node) -> MeshInstance3D:
|
|||
return null
|
||||
|
||||
|
||||
func _has_material_variant_override(
|
||||
root_node: Node,
|
||||
variants: Array[Material],
|
||||
) -> bool:
|
||||
if root_node == null:
|
||||
return false
|
||||
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():
|
||||
var override := mesh_instance.get_surface_override_material(
|
||||
surface_index
|
||||
)
|
||||
if override != null and override in variants:
|
||||
return true
|
||||
for child: Node in root_node.get_children():
|
||||
if _has_material_variant_override(child, variants):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _validate_authored_chunk_surfaces(
|
||||
region: GeneratedWorldRegion,
|
||||
generator: TerrainChunkGenerator,
|
||||
|
|
@ -329,6 +469,7 @@ func _validate_authored_chunk_surfaces(
|
|||
var found_grass_ocean_edge := false
|
||||
var found_grass_beach_transition := false
|
||||
var found_grass_ocean_corner := false
|
||||
var found_beach_ocean_corner := false
|
||||
for chunk_root: Node in generated.get_children():
|
||||
if chunk_root.name.begins_with("chunk_0002r"):
|
||||
var beach := chunk_root.find_child(
|
||||
|
|
@ -383,11 +524,20 @@ func _validate_authored_chunk_surfaces(
|
|||
assert("grass_lite" in corner_materials)
|
||||
assert("cliff_wall" in corner_materials)
|
||||
found_grass_ocean_corner = true
|
||||
elif chunk_root.name.begins_with("chunk_0008r"):
|
||||
var beach_ocean_corner := chunk_root.find_child(
|
||||
"chunk_0008", true, false
|
||||
) as MeshInstance3D
|
||||
assert(beach_ocean_corner != null and beach_ocean_corner.mesh != null)
|
||||
var beach_corner_materials := _material_names(beach_ocean_corner)
|
||||
assert("sand" in beach_corner_materials)
|
||||
found_beach_ocean_corner = true
|
||||
assert(found_beach)
|
||||
assert(found_pond)
|
||||
assert(found_grass_ocean_edge)
|
||||
assert(found_grass_beach_transition)
|
||||
assert(found_grass_ocean_corner)
|
||||
assert(found_beach_ocean_corner)
|
||||
|
||||
|
||||
func _material_names(mesh_instance: MeshInstance3D) -> PackedStringArray:
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ func _make_generator() -> TerrainChunkGenerator:
|
|||
"chunk_0005",
|
||||
"chunk_0006",
|
||||
"chunk_0007",
|
||||
"chunk_0008",
|
||||
]
|
||||
)
|
||||
return generator
|
||||
|
|
|
|||
|
|
@ -21,12 +21,13 @@ shadow_enabled = true
|
|||
[node name="TerrainChunkGenerator" type="Node3D" parent="."]
|
||||
script = ExtResource("2_generator")
|
||||
catalog = ExtResource("3_catalog")
|
||||
grid_size = Vector2i(7, 7)
|
||||
grid_size = Vector2i(11, 9)
|
||||
generation_seed = 13001
|
||||
build_collision = true
|
||||
show_chunk_labels = false
|
||||
force_center_chunk_id = &"chunk_spawn"
|
||||
required_chunk_ids = PackedStringArray("chunk_spawn", "chunk_0001", "chunk_0002", "chunk_0003", "chunk_0004", "chunk_0005", "chunk_0006", "chunk_0007")
|
||||
required_chunk_ids = PackedStringArray("chunk_spawn", "chunk_0001", "chunk_0002", "chunk_0003", "chunk_0004", "chunk_0005", "chunk_0006", "chunk_0007", "chunk_0008")
|
||||
elevated_cliff_feature_enabled = true
|
||||
|
||||
[node name="Player" parent="." instance=ExtResource("4_player")]
|
||||
position = Vector3(0, 0.3, 0)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ const EXPECTED_IDS: Array[String] = [
|
|||
"chunk_0005",
|
||||
"chunk_0006",
|
||||
"chunk_0007",
|
||||
"chunk_0008",
|
||||
"chunk_0009",
|
||||
"chunk_0010",
|
||||
"chunk_0011",
|
||||
"chunk_0012",
|
||||
"chunk_spawn",
|
||||
]
|
||||
const REQUIRED_IDS: Array[String] = [
|
||||
|
|
@ -23,10 +28,11 @@ const REQUIRED_IDS: Array[String] = [
|
|||
"chunk_0005",
|
||||
"chunk_0006",
|
||||
"chunk_0007",
|
||||
"chunk_0008",
|
||||
]
|
||||
const TEST_SEED := 13001
|
||||
const CONNECTOR_STRESS_SEED := 287
|
||||
const EXPECTED_SOLVER_VARIANT_COUNT := 27
|
||||
const EXPECTED_SOLVER_VARIANT_COUNT := 31
|
||||
const EXPECTED_VARIANT_COUNTS: Dictionary[StringName, int] = {
|
||||
&"chunk_0000": 4,
|
||||
&"chunk_0001": 4,
|
||||
|
|
@ -36,6 +42,11 @@ const EXPECTED_VARIANT_COUNTS: Dictionary[StringName, int] = {
|
|||
&"chunk_0005": 4,
|
||||
&"chunk_0006": 4,
|
||||
&"chunk_0007": 4,
|
||||
&"chunk_0008": 4,
|
||||
&"chunk_0009": 4,
|
||||
&"chunk_0010": 4,
|
||||
&"chunk_0011": 4,
|
||||
&"chunk_0012": 4,
|
||||
&"chunk_spawn": 1,
|
||||
}
|
||||
|
||||
|
|
@ -75,6 +86,11 @@ func _validate_catalog() -> void:
|
|||
var grass_ocean_edge := CATALOG.definition_for_id(&"chunk_0005")
|
||||
var grass_beach_transition := CATALOG.definition_for_id(&"chunk_0006")
|
||||
var grass_ocean_corner := CATALOG.definition_for_id(&"chunk_0007")
|
||||
var beach_ocean_corner := CATALOG.definition_for_id(&"chunk_0008")
|
||||
var cliff_top := CATALOG.definition_for_id(&"chunk_0009")
|
||||
var cliff_corner := CATALOG.definition_for_id(&"chunk_0010")
|
||||
var cliff_edge := CATALOG.definition_for_id(&"chunk_0011")
|
||||
var cliff_ramp := CATALOG.definition_for_id(&"chunk_0012")
|
||||
var spawn := CATALOG.definition_for_id(&"chunk_spawn")
|
||||
_check(
|
||||
(
|
||||
|
|
@ -84,6 +100,11 @@ func _validate_catalog() -> void:
|
|||
and grass_ocean_edge != null
|
||||
and grass_beach_transition != null
|
||||
and grass_ocean_corner != null
|
||||
and beach_ocean_corner != null
|
||||
and cliff_top != null
|
||||
and cliff_corner != null
|
||||
and cliff_edge != null
|
||||
and cliff_ramp != null
|
||||
and spawn != null
|
||||
),
|
||||
"The authored biome-rule definitions must be available.",
|
||||
|
|
@ -95,6 +116,11 @@ func _validate_catalog() -> void:
|
|||
and grass_ocean_edge != null
|
||||
and grass_beach_transition != null
|
||||
and grass_ocean_corner != null
|
||||
and beach_ocean_corner != null
|
||||
and cliff_top != null
|
||||
and cliff_corner != null
|
||||
and cliff_edge != null
|
||||
and cliff_ramp != null
|
||||
and spawn != null
|
||||
):
|
||||
_check(
|
||||
|
|
@ -193,6 +219,45 @@ func _validate_catalog() -> void:
|
|||
),
|
||||
"Both corner land seams must accept straight grass ocean edges.",
|
||||
)
|
||||
_check(
|
||||
beach_ocean_corner.ocean_facing_edges
|
||||
== (
|
||||
(1 << int(TerrainChunkTopology.Edge.EAST))
|
||||
| (1 << int(TerrainChunkTopology.Edge.SOUTH))
|
||||
),
|
||||
"The authored beach corner must expose east and south to ocean.",
|
||||
)
|
||||
_check(
|
||||
beach_ocean_corner.minimum_required_neighbors == 2
|
||||
and (
|
||||
"beach_ocean_edge"
|
||||
in beach_ocean_corner.required_neighbor_tags
|
||||
),
|
||||
"The beach corner must join two straight beach ocean edges.",
|
||||
)
|
||||
for cliff_definition: TerrainChunkDefinition in [
|
||||
cliff_top,
|
||||
cliff_corner,
|
||||
cliff_edge,
|
||||
cliff_ramp,
|
||||
]:
|
||||
_check(
|
||||
cliff_definition.overlay_only
|
||||
and cliff_definition.must_be_interior
|
||||
and cliff_definition.base_layer_scene != null
|
||||
and cliff_definition.base_layer_mesh_name == &"chunk_0000",
|
||||
"Every second-tier piece must overlay level-one grass inland.",
|
||||
)
|
||||
_check(
|
||||
cliff_top.minimum_required_neighbors == 4
|
||||
and "elevation_2" in cliff_top.required_neighbor_tags,
|
||||
"The second-tier top must be enclosed on all four sides.",
|
||||
)
|
||||
_check(
|
||||
"ramp" in cliff_ramp.tags
|
||||
and cliff_ramp.maximum_placements > 0,
|
||||
"The second-tier ramp must remain available without being required.",
|
||||
)
|
||||
|
||||
|
||||
func _validate_profiles() -> void:
|
||||
|
|
@ -443,11 +508,13 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
|
|||
var grass_ocean_edge := CATALOG.definition_for_id(&"chunk_0005")
|
||||
var grass_beach_transition := CATALOG.definition_for_id(&"chunk_0006")
|
||||
var grass_ocean_corner := CATALOG.definition_for_id(&"chunk_0007")
|
||||
var beach_ocean_corner := CATALOG.definition_for_id(&"chunk_0008")
|
||||
_check(
|
||||
(
|
||||
grass_ocean_edge != null
|
||||
and grass_beach_transition != null
|
||||
and grass_ocean_corner != null
|
||||
and beach_ocean_corner != null
|
||||
),
|
||||
"The authored coastline additions must be available.",
|
||||
)
|
||||
|
|
@ -455,6 +522,7 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
|
|||
grass_ocean_edge == null
|
||||
or grass_beach_transition == null
|
||||
or grass_ocean_corner == null
|
||||
or beach_ocean_corner == null
|
||||
):
|
||||
return
|
||||
var beach_zero := _find_variant(generator, &"chunk_0002", 0)
|
||||
|
|
@ -462,12 +530,14 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
|
|||
var grass_edge_south := _find_variant(generator, &"chunk_0005", 3)
|
||||
var transition_zero := _find_variant(generator, &"chunk_0006", 0)
|
||||
var corner_zero := _find_variant(generator, &"chunk_0007", 0)
|
||||
var beach_corner_zero := _find_variant(generator, &"chunk_0008", 0)
|
||||
_check(
|
||||
beach_zero != null
|
||||
and grass_edge_zero != null
|
||||
and grass_edge_south != null
|
||||
and transition_zero != null
|
||||
and corner_zero != null,
|
||||
and corner_zero != null
|
||||
and beach_corner_zero != null,
|
||||
"The unrotated coastline variants must be available.",
|
||||
)
|
||||
if (
|
||||
|
|
@ -476,6 +546,7 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
|
|||
and grass_edge_south != null
|
||||
and transition_zero != null
|
||||
and corner_zero != null
|
||||
and beach_corner_zero != null
|
||||
):
|
||||
_check(
|
||||
grass_edge_zero.profile(
|
||||
|
|
@ -522,6 +593,24 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
|
|||
),
|
||||
"The corner's west side must join a straight grass ocean edge.",
|
||||
)
|
||||
_check(
|
||||
beach_corner_zero.profile(TerrainChunkTopology.Edge.NORTH).matches(
|
||||
beach_zero.profile(TerrainChunkTopology.Edge.SOUTH),
|
||||
generator.edge_match_tolerance,
|
||||
),
|
||||
"The beach corner's north side must join a straight beach.",
|
||||
)
|
||||
var beach_south := _find_variant(generator, &"chunk_0002", 3)
|
||||
_check(
|
||||
beach_south != null
|
||||
and beach_corner_zero.profile(
|
||||
TerrainChunkTopology.Edge.WEST
|
||||
).matches(
|
||||
beach_south.profile(TerrainChunkTopology.Edge.EAST),
|
||||
generator.edge_match_tolerance,
|
||||
),
|
||||
"The beach corner's west side must join a rotated straight beach.",
|
||||
)
|
||||
var flat_grass := _find_variant(generator, &"chunk_0000", 0)
|
||||
var flat_sand := _find_variant(generator, &"chunk_0001", 0)
|
||||
_check(
|
||||
|
|
@ -560,7 +649,12 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
|
|||
),
|
||||
"No transition rotation may accept sand behind it.",
|
||||
)
|
||||
for stable_id: StringName in [&"chunk_0005", &"chunk_0006", &"chunk_0007"]:
|
||||
for stable_id: StringName in [
|
||||
&"chunk_0005",
|
||||
&"chunk_0006",
|
||||
&"chunk_0007",
|
||||
&"chunk_0008",
|
||||
]:
|
||||
for quarter_turns: int in 4:
|
||||
var coast_variant := _find_variant(
|
||||
generator,
|
||||
|
|
@ -580,11 +674,15 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
|
|||
),
|
||||
"%s must never place its ocean edge inside the map." % stable_id,
|
||||
)
|
||||
if stable_id != &"chunk_0007":
|
||||
if stable_id != &"chunk_0007" and stable_id != &"chunk_0008":
|
||||
continue
|
||||
var boundary_coordinate := Vector2i(3, 3)
|
||||
var ocean_edges := coast_variant.rotated_edge_mask(
|
||||
grass_ocean_corner.ocean_facing_edges
|
||||
(
|
||||
grass_ocean_corner.ocean_facing_edges
|
||||
if stable_id == &"chunk_0007"
|
||||
else beach_ocean_corner.ocean_facing_edges
|
||||
)
|
||||
)
|
||||
for edge_value: int in TerrainChunkTopology.Edge.values():
|
||||
if (ocean_edges & (1 << edge_value)) == 0:
|
||||
|
|
@ -603,15 +701,15 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
|
|||
coast_variant,
|
||||
boundary_coordinate,
|
||||
),
|
||||
"Each grass corner rotation must fit its matching map corner.",
|
||||
"Each coast corner rotation must fit its matching map corner.",
|
||||
)
|
||||
|
||||
|
||||
func _validate_generation_summary(generator: TerrainChunkGenerator) -> void:
|
||||
var summary := generator._build_summary()
|
||||
_check(
|
||||
int(summary.get("variant_count", 0)) == 33,
|
||||
"The current catalog must expose all 33 authored rotations.",
|
||||
int(summary.get("variant_count", 0)) == 53,
|
||||
"The current catalog must expose all 53 authored rotations.",
|
||||
)
|
||||
_check(
|
||||
int(summary.get("solver_variant_count", 0))
|
||||
|
|
@ -811,6 +909,27 @@ func _validate_layout_rules(generator: TerrainChunkGenerator) -> void:
|
|||
straight_edge_neighbors == 2,
|
||||
"Every grass corner must join two straight grass ocean edges.",
|
||||
)
|
||||
if placement.definition.stable_id == &"chunk_0008":
|
||||
var straight_beach_neighbors := 0
|
||||
for edge_value: int in TerrainChunkTopology.Edge.values():
|
||||
var neighbor_coordinate := (
|
||||
coordinate
|
||||
+ TerrainChunkTopology.grid_offset(
|
||||
edge_value as TerrainChunkTopology.Edge
|
||||
)
|
||||
)
|
||||
if not generator._coordinate_is_inside_grid(neighbor_coordinate):
|
||||
continue
|
||||
var neighbor := generator._placements[
|
||||
neighbor_coordinate.y * generator.grid_size.x
|
||||
+ neighbor_coordinate.x
|
||||
]
|
||||
if neighbor.definition.stable_id == &"chunk_0002":
|
||||
straight_beach_neighbors += 1
|
||||
_check(
|
||||
straight_beach_neighbors == 2,
|
||||
"Every beach corner must join two straight beach ocean edges.",
|
||||
)
|
||||
if placement.definition.stable_id != &"chunk_0001":
|
||||
continue
|
||||
var touches_coast := false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue