fix: close generated coastlines and extend cast bounds

This commit is contained in:
Alexander Sellite 2026-08-21 22:12:14 -04:00
parent 2c17b7b377
commit f85e9bceeb
16 changed files with 250 additions and 57 deletions

View file

@ -116,40 +116,31 @@ func _validate_generated_region(
var grass_coast_count := _placement_count(placements, "chunk_0005")
var grass_corner_count := _placement_count(placements, "chunk_0007")
var beach_corner_count := _placement_count(placements, "chunk_0008")
assert((beach_count > 0) != (grass_coast_count > 0))
if beach_count > 0:
assert(beach_count == 48 and grass_coast_count == 0)
assert(beach_corner_count == 4 and grass_corner_count == 0)
assert(_placement_count(placements, "chunk_0009") == 9)
assert(_placement_count(placements, "chunk_0010") == 4)
assert(
_placement_count(placements, "chunk_0011")
+ _placement_count(placements, "chunk_0012")
== 12
assert(beach_count == 44 and grass_coast_count == 0)
assert(beach_corner_count == 3 and grass_corner_count == 0)
assert(_placement_count(placements, "chunk_0009") == 10)
assert(_placement_count(placements, "chunk_0010") == 5)
assert(
_placement_count(placements, "chunk_0011")
+ _placement_count(placements, "chunk_0012")
== 14
)
assert(_placement_count(placements, "chunk_0012") == 2)
assert(_placement_count(placements, "chunk_0014") == 2)
assert(_placement_count(placements, "chunk_0015") == 1)
assert(_placement_count(placements, "chunk_0017") == 0)
assert(_placement_count(placements, "chunk_0018") == 0)
assert(_placement_count(placements, "chunk_0019") == 1)
assert(_placement_count(placements, "chunk_0020") == 1)
for index: int in placements.size():
var coordinate := Vector2i(
index % generator.grid_size.x,
index / generator.grid_size.x,
)
assert(_placement_count(placements, "chunk_0012") == 1)
for stable_id: String in [
"chunk_0014",
"chunk_0015",
"chunk_0017",
"chunk_0018",
]:
assert(_placement_count(placements, stable_id) == 0)
else:
assert(grass_coast_count == 44 and beach_count == 0)
assert(grass_corner_count == 3 and beach_corner_count == 0)
assert(_placement_count(placements, "chunk_0009") == 10)
assert(_placement_count(placements, "chunk_0010") == 5)
assert(
_placement_count(placements, "chunk_0011")
+ _placement_count(placements, "chunk_0012")
== 14
)
assert(_placement_count(placements, "chunk_0012") == 2)
assert(_placement_count(placements, "chunk_0014") == 2)
assert(_placement_count(placements, "chunk_0015") == 1)
assert(_placement_count(placements, "chunk_0017") == 1)
assert(_placement_count(placements, "chunk_0018") == 1)
if placements[index].begins_with("chunk_0001@"):
assert(generator._distance_from_map_boundary(coordinate) <= 1)
elif placements[index].begins_with("chunk_0013@"):
assert(generator._distance_from_map_boundary(coordinate) <= 2)
assert(_placement_count(placements, "chunk_0013") >= 1)
assert(
generator.get_generated_chunks_root().get_child_count()
@ -362,6 +353,8 @@ func _validate_elevated_cliff_feature(
&"chunk_0015",
&"chunk_0017",
&"chunk_0018",
&"chunk_0019",
&"chunk_0020",
]
var has_coastal_feature := false
for record: Dictionary in generator.placement_records():
@ -375,6 +368,8 @@ func _validate_elevated_cliff_feature(
&"chunk_0015",
&"chunk_0017",
&"chunk_0018",
&"chunk_0019",
&"chunk_0020",
]:
continue
var coordinate: Vector2i = record.get("coordinate", Vector2i.ZERO)
@ -482,6 +477,8 @@ func _validate_elevated_cliff_feature(
&"chunk_0015",
&"chunk_0017",
&"chunk_0018",
&"chunk_0019",
&"chunk_0020",
]:
continue
if stable_id in [&"chunk_0014", &"chunk_0015"]:
@ -491,14 +488,27 @@ func _validate_elevated_cliff_feature(
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 is_transition := stable_id in [&"chunk_0017", &"chunk_0018"]
var transition_base_mesh := &"chunk_0000"
if stable_id in [&"chunk_0017", &"chunk_0018"]:
transition_base_mesh = &"chunk_0007"
elif stable_id in [&"chunk_0019", &"chunk_0020"]:
transition_base_mesh = &"chunk_0008"
var base_mesh := TerrainChunkAnalyzer.find_primary_mesh(
base_layer,
&"chunk_0005" if is_transition else &"chunk_0000",
transition_base_mesh,
)
var overlay_mesh := TerrainChunkAnalyzer.find_primary_mesh(
overlay,
&"chunk_0015" if is_transition else stable_id,
(
&"chunk_0015"
if stable_id in [
&"chunk_0017",
&"chunk_0018",
&"chunk_0019",
&"chunk_0020",
]
else stable_id
),
)
assert(base_mesh != null and base_mesh.mesh != null)
assert(overlay_mesh != null and overlay_mesh.mesh != null)

View file

@ -113,6 +113,7 @@ func _make_generator() -> TerrainChunkGenerator:
[
"chunk_spawn",
"chunk_0001",
"chunk_0002",
"chunk_0003",
"chunk_0004",
]

View file

@ -26,7 +26,7 @@ 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_0003", "chunk_0004")
required_chunk_ids = PackedStringArray("chunk_spawn", "chunk_0001", "chunk_0002", "chunk_0003", "chunk_0004")
grass_sand_smoothing_enabled = true
elevated_cliff_feature_enabled = true

View file

@ -23,11 +23,14 @@ const EXPECTED_IDS: Array[String] = [
"chunk_0016",
"chunk_0017",
"chunk_0018",
"chunk_0019",
"chunk_0020",
"chunk_spawn",
]
const REQUIRED_IDS: Array[String] = [
"chunk_spawn",
"chunk_0001",
"chunk_0002",
"chunk_0003",
"chunk_0004",
]
@ -54,6 +57,8 @@ const EXPECTED_VARIANT_COUNTS: Dictionary[StringName, int] = {
&"chunk_0016": 4,
&"chunk_0017": 4,
&"chunk_0018": 4,
&"chunk_0019": 4,
&"chunk_0020": 4,
&"chunk_spawn": 1,
}
@ -101,6 +106,8 @@ func _validate_catalog() -> void:
var cliff_sea_corner := CATALOG.definition_for_id(&"chunk_0015")
var cliff_sea_transition_right := CATALOG.definition_for_id(&"chunk_0017")
var cliff_sea_transition_left := CATALOG.definition_for_id(&"chunk_0018")
var cliff_beach_transition_right := CATALOG.definition_for_id(&"chunk_0019")
var cliff_beach_transition_left := CATALOG.definition_for_id(&"chunk_0020")
var stream_variant := CATALOG.definition_for_id(&"chunk_0016")
var cliff_top := CATALOG.definition_for_id(&"chunk_0009")
var cliff_corner := CATALOG.definition_for_id(&"chunk_0010")
@ -122,6 +129,8 @@ func _validate_catalog() -> void:
and cliff_sea_corner != null
and cliff_sea_transition_right != null
and cliff_sea_transition_left != null
and cliff_beach_transition_right != null
and cliff_beach_transition_left != null
and stream_variant != null
and cliff_top != null
and cliff_corner != null
@ -145,6 +154,8 @@ func _validate_catalog() -> void:
and cliff_sea_corner != null
and cliff_sea_transition_right != null
and cliff_sea_transition_left != null
and cliff_beach_transition_right != null
and cliff_beach_transition_left != null
and stream_variant != null
and cliff_top != null
and cliff_corner != null
@ -168,8 +179,12 @@ func _validate_catalog() -> void:
(
"sand" in sand.required_neighbor_tags
and "coast" in sand.required_neighbor_tags
and sand.maximum_boundary_distance == 1
),
(
"Every flat-sand chunk must remain attached to sand or authored "
+ "coast within the first inland terrain ring."
),
"Every flat-sand chunk must remain attached to sand or authored coast.",
)
_check(
spawn.minimum_required_neighbors == 3,
@ -270,6 +285,7 @@ func _validate_catalog() -> void:
_check(
grass_sand_diagonal.must_be_interior
and not grass_sand_diagonal.participates_in_base_solver
and grass_sand_diagonal.maximum_boundary_distance == 2
and "mixed_surface" in grass_sand_diagonal.tags,
(
"The grass-sand diagonal must remain an inland post-process "
@ -355,7 +371,7 @@ func _validate_catalog() -> void:
_check(
transition.overlay_only
and transition.base_layer_scene != null
and transition.base_layer_mesh_name == &"chunk_0005"
and transition.base_layer_mesh_name == &"chunk_0007"
and not transition.must_be_interior
and transition.prefers_map_boundary
and "transition" in transition.tags,
@ -371,11 +387,37 @@ func _validate_catalog() -> void:
"The right coastal transition must align its south-facing base coast.",
)
_check(
cliff_sea_transition_left.base_layer_quarter_turns == 0
cliff_sea_transition_left.base_layer_quarter_turns == 1
and cliff_sea_transition_left.ocean_facing_edges
== (1 << int(TerrainChunkTopology.Edge.EAST)),
"The left coastal transition must align its east-facing base coast.",
)
for transition: TerrainChunkDefinition in [
cliff_beach_transition_right,
cliff_beach_transition_left,
]:
_check(
transition.overlay_only
and transition.base_layer_scene != null
and transition.base_layer_mesh_name == &"chunk_0008"
and not transition.must_be_interior
and transition.prefers_map_boundary
and "sand" in transition.tags
and "transition" in transition.tags,
(
"Each raised beach endpoint must close over an authored "
+ "level-one beach corner."
),
)
_check(
cliff_beach_transition_right.base_layer_quarter_turns == 3
and cliff_beach_transition_right.ocean_facing_edges
== (1 << int(TerrainChunkTopology.Edge.SOUTH))
and cliff_beach_transition_left.base_layer_quarter_turns == 1
and cliff_beach_transition_left.ocean_facing_edges
== (1 << int(TerrainChunkTopology.Edge.EAST)),
"The raised beach endpoint corners must face their open coastline.",
)
_check(
cliff_sea_edge.ocean_facing_edges
== (1 << int(TerrainChunkTopology.Edge.EAST)),
@ -1066,6 +1108,8 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
&"chunk_0015",
&"chunk_0017",
&"chunk_0018",
&"chunk_0019",
&"chunk_0020",
]:
for quarter_turns: int in 4:
var coast_variant := _find_variant(
@ -1117,8 +1161,8 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void:
func _validate_generation_summary(generator: TerrainChunkGenerator) -> void:
var summary := generator._build_summary()
_check(
int(summary.get("variant_count", 0)) == 77,
"The current catalog must expose all 77 authored rotations.",
int(summary.get("variant_count", 0)) == 85,
"The current catalog must expose all 85 authored rotations.",
)
_check(
int(summary.get("solver_variant_count", 0))

View file

@ -86,6 +86,7 @@ func _validate_world_switching() -> void:
assert(world.get_world_layout() == WorldLayout.GENERATED)
assert(world.get_fishing_shop() != null)
assert(world.get_player_storage() != null)
_validate_world_boundary_clearance(world)
assert(world.activate_world(WorldLayout.STARTER_ISLAND, 13579))
assert(world.get_world_layout() == WorldLayout.STARTER_ISLAND)
assert(world.get_generation_seed() == 13579)
@ -103,6 +104,26 @@ func _validate_world_switching() -> void:
await process_frame
func _validate_world_boundary_clearance(world: TestWorld) -> void:
var active_region := world.get("_active_region") as WorldRegion
assert(active_region != null)
var half := active_region.get_playable_half_extents()
var north := world.get_node("WorldBounds/North") as StaticBody3D
var south := world.get_node("WorldBounds/South") as StaticBody3D
var west := world.get_node("WorldBounds/West") as StaticBody3D
var east := world.get_node("WorldBounds/East") as StaticBody3D
var fishing_defaults := FishingSpot.new()
assert(
TestWorld.WORLD_BOUNDARY_SHORELINE_CLEARANCE
> fishing_defaults.maximum_cast_distance + 1.0
)
fishing_defaults.free()
assert(north.position.z - half.y >= 18.0)
assert(-south.position.z - half.y >= 18.0)
assert(-west.position.x - half.x >= 18.0)
assert(east.position.x - half.x >= 18.0)
func _validate_network_metadata() -> void:
var hello: Dictionary = NetworkProtocol.make_server_hello(
true,