diff --git a/tests/generated_world_runtime_validation.gd b/tests/generated_world_runtime_validation.gd index 0d7d26f..82627a5 100644 --- a/tests/generated_world_runtime_validation.gd +++ b/tests/generated_world_runtime_validation.gd @@ -136,17 +136,30 @@ func _validate_generated_region( assert(maxi( generator._river_feature_footprint_size.x, generator._river_feature_footprint_size.y, - ) >= 7) + ) >= 4) assert(mini( generator._river_feature_footprint_size.x, generator._river_feature_footprint_size.y, - ) == 2) + ) >= 4) assert(generator._river_feature_flow_direction in [ Vector2i.RIGHT, Vector2i.DOWN, Vector2i.LEFT, Vector2i.UP, ]) + assert(generator._river_feature_outlet_direction in [ + Vector2i.RIGHT, + Vector2i.DOWN, + Vector2i.LEFT, + Vector2i.UP, + ]) + assert( + generator._river_feature_flow_direction.x + * generator._river_feature_outlet_direction.x + + generator._river_feature_flow_direction.y + * generator._river_feature_outlet_direction.y + == 0 + ) assert(generator.elevated_cliff_coastal_feature_required) assert(placements.size() == expected_chunk_count) assert(placements[center_index].begins_with("chunk_spawn@")) @@ -226,6 +239,10 @@ func _validate_generated_region( assert(_placement_count(placements, "chunk_0030") == 1) assert(_placement_count(placements, "chunk_0031") == 1) assert(_placement_count(placements, "chunk_0032") == 1) + assert(_placement_count(placements, "chunk_0033") == 1) + assert(_placement_count(placements, "chunk_0034") == 1) + assert(_placement_count(placements, "chunk_0035") == 1) + assert(_placement_count(placements, "chunk_0036") == 1) assert( _placement_count(placements, "chunk_0014") == (2 if has_secondary_elevation else 0) @@ -239,12 +256,15 @@ func _validate_generated_region( assert(_placement_count(placements, "chunk_0022") == 4) assert(_placement_count(placements, "chunk_0023") == 4) var lake_edge_count := _placement_count(placements, "chunk_0017") + var lake_edge_variant_count := _placement_count(placements, "chunk_0037") var lake_fill_count := _placement_count(placements, "chunk_0019") var lake_narrow_count := _placement_count(placements, "chunk_0021") var lake_size := generator._lake_feature_footprint_size.x assert(lake_size in [7, 8]) assert(lake_fill_count == (lake_size - 2) * (lake_size - 2)) - assert(lake_edge_count == (lake_size - 6) * 4) + assert(lake_edge_count + lake_edge_variant_count == (lake_size - 6) * 4) + assert(lake_edge_count > 0) + assert(lake_edge_variant_count > 0) assert(lake_narrow_count == 8) assert(_placement_count(placements, "chunk_9999") == 0) assert(_placement_count(placements, "chunk_9998") == 0) @@ -257,13 +277,14 @@ func _validate_generated_region( == (1 if has_secondary_elevation else 0) ) assert(_placement_count(placements, "chunk_9995") == 0) - var river_length := maxi( - generator._river_feature_footprint_size.x, - generator._river_feature_footprint_size.y, + var river_coordinate_count := generator._river_feature_coordinates.size() + var river_edge_count := ( + _placement_count(placements, "chunk_0024") + + _placement_count(placements, "chunk_0025") ) - assert(river_length in [7, 8]) - assert(_placement_count(placements, "chunk_0024") == river_length - 2) - assert(_placement_count(placements, "chunk_0025") == river_length - 2) + assert(river_coordinate_count >= 12) + assert(generator._river_feature_placements.size() == river_coordinate_count) + assert(river_edge_count == river_coordinate_count - 8) var river_source_coordinates := generator._river_source_coordinates( generator._river_feature_origin, generator._river_feature_footprint_size, @@ -297,7 +318,7 @@ func _validate_generated_region( assert( not generator._coordinate_is_inside_grid( outlet_coordinate - + generator._river_feature_flow_direction + + generator._river_feature_outlet_direction ) ) assert(outlet_coordinates.size() == 2) @@ -379,7 +400,7 @@ func _validate_generated_region( ] = surface_polygon.size() _validate_complete_coastline(generator) assert(fresh_root.get_child_count() == fresh_placement_count) - assert(river_placement_count == river_length * 2) + assert(river_placement_count == river_coordinate_count) assert( polygon_sizes_by_coordinate.size() == 20 + river_placement_count @@ -1025,19 +1046,48 @@ func _validate_decoration_transform( prop.global_position + Vector3.DOWN * 8.0, 1, ) - var prop_body := prop.get_node_or_null( - "TrunkCollision", - ) as CollisionObject3D - if prop_body != null: - query.exclude = [prop_body.get_rid()] + var excluded_colliders: Array[RID] = [] + var decorations := region.get_node("Decorations") as Node3D + for decoration: Node in decorations.get_children(): + var prop_body := decoration.get_node_or_null( + "TrunkCollision", + ) as CollisionObject3D + if prop_body != null: + excluded_colliders.append(prop_body.get_rid()) + query.exclude = excluded_colliders var hit := region.get_world_3d().direct_space_state.intersect_ray(query) + # Stacked cliff walls can overhang a neighboring cell. Match the placement + # sampler by ignoring steep faces until the ray reaches walkable terrain. + while ( + not hit.is_empty() + and absf((hit.get("normal", Vector3.ZERO) as Vector3).dot(Vector3.UP)) + < 0.35 + ): + var steep_collider := hit.get("collider") as CollisionObject3D + assert(steep_collider != null) + excluded_colliders.append(steep_collider.get_rid()) + query.exclude = excluded_colliders + hit = region.get_world_3d().direct_space_state.intersect_ray(query) assert( not hit.is_empty(), "No terrain collision below %s (%s) at %s." % [prop.name, definition.stable_id, prop.global_position], ) var ground_position: Vector3 = hit["position"] - assert(absf(ground_position.y - prop.global_position.y) <= 0.01) + assert( + absf(ground_position.y - prop.global_position.y) <= 0.01, + "Terrain height %s does not match %s (%s) at %s." + % [ + ground_position.y, + prop.name, + definition.stable_id, + "%s in chunk %s; hit %s" % [ + prop.global_position, + prop.get_meta(&"terrain_chunk_coordinate", Vector2i(-1, -1)), + (hit.get("collider") as Node).get_path(), + ], + ], + ) func _validate_tree_gatherable_anchors( diff --git a/tests/terrain_chunk_generator_validation.gd b/tests/terrain_chunk_generator_validation.gd index e8bf158..b8d24cf 100644 --- a/tests/terrain_chunk_generator_validation.gd +++ b/tests/terrain_chunk_generator_validation.gd @@ -37,6 +37,11 @@ const EXPECTED_IDS: Array[String] = [ "chunk_0030", "chunk_0031", "chunk_0032", + "chunk_0033", + "chunk_0034", + "chunk_0035", + "chunk_0036", + "chunk_0037", "chunk_9999", "chunk_9998", "chunk_9997", @@ -88,6 +93,11 @@ const EXPECTED_VARIANT_COUNTS: Dictionary[StringName, int] = { &"chunk_0030": 4, &"chunk_0031": 4, &"chunk_0032": 4, + &"chunk_0033": 4, + &"chunk_0034": 4, + &"chunk_0035": 4, + &"chunk_0036": 4, + &"chunk_0037": 4, &"chunk_9999": 4, &"chunk_9998": 4, &"chunk_9997": 4, @@ -144,6 +154,7 @@ func _validate_catalog() -> void: var cliff_beach_transition_left := CATALOG.definition_for_id(&"chunk_9996") var stream_variant := CATALOG.definition_for_id(&"chunk_0016") var lake_edge := CATALOG.definition_for_id(&"chunk_0017") + var lake_edge_variant := CATALOG.definition_for_id(&"chunk_0037") var lake_corner := CATALOG.definition_for_id(&"chunk_0018") var lake_fill := CATALOG.definition_for_id(&"chunk_0019") var lake_diagonal := CATALOG.definition_for_id(&"chunk_0020") @@ -156,6 +167,10 @@ func _validate_catalog() -> void: var river_source_left := CATALOG.definition_for_id(&"chunk_0030") var river_outlet_right := CATALOG.definition_for_id(&"chunk_0031") var river_outlet_left := CATALOG.definition_for_id(&"chunk_0032") + var river_bend_c := CATALOG.definition_for_id(&"chunk_0033") + var river_bend_b := CATALOG.definition_for_id(&"chunk_0034") + var river_bend_a := CATALOG.definition_for_id(&"chunk_0035") + var river_bend_d := CATALOG.definition_for_id(&"chunk_0036") var river_cap := CATALOG.definition_for_id(&"chunk_9995") var cliff_top := CATALOG.definition_for_id(&"chunk_0009") var cliff_corner := CATALOG.definition_for_id(&"chunk_0010") @@ -184,6 +199,7 @@ func _validate_catalog() -> void: and cliff_beach_transition_left != null and stream_variant != null and lake_edge != null + and lake_edge_variant != null and lake_corner != null and lake_fill != null and lake_diagonal != null @@ -196,6 +212,10 @@ func _validate_catalog() -> void: and river_source_left != null and river_outlet_right != null and river_outlet_left != null + and river_bend_a != null + and river_bend_b != null + and river_bend_c != null + and river_bend_d != null and river_cap != null and cliff_top != null and cliff_corner != null @@ -226,6 +246,7 @@ func _validate_catalog() -> void: and cliff_beach_transition_left != null and stream_variant != null and lake_edge != null + and lake_edge_variant != null and lake_corner != null and lake_fill != null and lake_diagonal != null @@ -238,6 +259,10 @@ func _validate_catalog() -> void: and river_source_left != null and river_outlet_right != null and river_outlet_left != null + and river_bend_a != null + and river_bend_b != null + and river_bend_c != null + and river_bend_d != null and river_cap != null and cliff_top != null and cliff_corner != null @@ -431,6 +456,7 @@ func _validate_catalog() -> void: _check( ( not lake_edge.participates_in_base_solver + and not lake_edge_variant.participates_in_base_solver and not lake_corner.participates_in_base_solver and not lake_fill.participates_in_base_solver and not lake_diagonal.participates_in_base_solver @@ -439,6 +465,14 @@ func _validate_catalog() -> void: and not lake_narrow_to_regular.participates_in_base_solver and lake_edge.water_inlet_edges == lake_edge.water_outlet_edges and lake_edge.water_inlet_edges == 7 + and lake_edge_variant.water_inlet_edges + == lake_edge.water_inlet_edges + and lake_edge_variant.water_outlet_edges + == lake_edge.water_outlet_edges + and lake_edge_variant.water_surface_size + == lake_edge.water_surface_size + and lake_edge_variant.water_surface_offset + == lake_edge.water_surface_offset and lake_corner.water_inlet_edges == lake_corner.water_outlet_edges and lake_corner.water_inlet_edges == 6 @@ -461,6 +495,7 @@ func _validate_catalog() -> void: and lake_narrow_to_regular.water_outlet_edges == 14 and lake_narrow_to_regular.water_surface_polygon.size() == 5 and "lake" in lake_edge.tags + and "lake" in lake_edge_variant.tags and "lake" in lake_corner.tags and "lake" in lake_fill.tags and "lake" in lake_diagonal.tags @@ -478,6 +513,10 @@ func _validate_catalog() -> void: and not river_source_left.participates_in_base_solver and not river_outlet_right.participates_in_base_solver and not river_outlet_left.participates_in_base_solver + and not river_bend_a.participates_in_base_solver + and not river_bend_b.participates_in_base_solver + and not river_bend_c.participates_in_base_solver + and not river_bend_d.participates_in_base_solver and not river_cap.participates_in_base_solver and river_edge.water_inlet_edges == 14 and river_edge.water_outlet_edges == 14 @@ -491,6 +530,16 @@ func _validate_catalog() -> void: and river_outlet_right.water_outlet_edges == 14 and river_outlet_left.water_inlet_edges == 11 and river_outlet_left.water_outlet_edges == 11 + and river_bend_a.water_inlet_edges == 14 + and river_bend_a.water_outlet_edges == 14 + and river_bend_b.water_inlet_edges == 12 + and river_bend_b.water_outlet_edges == 12 + and river_bend_c.water_inlet_edges == 15 + and river_bend_c.water_outlet_edges == 15 + and river_bend_c.continuous_water_seam_edges == 15 + and river_bend_d.water_inlet_edges == 13 + and river_bend_d.water_outlet_edges == 13 + and river_bend_d.continuous_water_seam_edges == 1 and river_cap.water_inlet_edges == 6 and river_cap.water_outlet_edges == 6 and river_edge.water_surface_polygon.size() == 13 @@ -509,11 +558,15 @@ func _validate_catalog() -> void: and "river_source_left" in river_source_left.tags and "river_outlet_right" in river_outlet_right.tags and "river_outlet_left" in river_outlet_left.tags + and "river_bend_a" in river_bend_a.tags + and "river_bend_b" in river_bend_b.tags + and "river_bend_c" in river_bend_c.tags + and "river_bend_d" in river_bend_d.tags and "river" in river_cap.tags ), ( - "The river banks, cliff source, ocean outlet, and legacy caps " - + "must remain connected freshwater chunks." + "The river banks, bend, cliff source, ocean outlet, and legacy " + + "caps must remain connected freshwater chunks." ), ) for cliff_definition: TerrainChunkDefinition in [ @@ -1307,6 +1360,7 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void: var lake_regular_to_narrow := _find_variant(generator, &"chunk_0022", 0) var lake_narrow_to_regular := _find_variant(generator, &"chunk_0023", 0) var lake_regular_top := _find_variant(generator, &"chunk_0017", 3) + var lake_regular_variant_top := _find_variant(generator, &"chunk_0037", 3) _check( ( lake_diagonal_northwest != null @@ -1316,6 +1370,7 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void: and lake_regular_to_narrow != null and lake_narrow_to_regular != null and lake_regular_top != null + and lake_regular_variant_top != null ), "Every authored diagonal lake perimeter variant must be available.", ) @@ -1327,7 +1382,13 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void: and lake_regular_to_narrow != null and lake_narrow_to_regular != null and lake_regular_top != null + and lake_regular_variant_top != null ): + _check( + lake_regular_variant_top.topology_signature(0.001) + == lake_regular_top.topology_signature(0.001), + "Both regular lake edge visuals must expose identical seams.", + ) _check( generator._edges_are_compatible( lake_diagonal_northwest, @@ -1398,11 +1459,36 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void: var river_edge_top := _find_variant(generator, &"chunk_0024", 0) var river_edge_variant_top := _find_variant(generator, &"chunk_0025", 0) var river_edge_variant_bottom := _find_variant(generator, &"chunk_0025", 2) + var river_edge_vertical_left := _find_variant(generator, &"chunk_0024", 1) + var river_edge_vertical_right := _find_variant(generator, &"chunk_0025", 3) var river_source_right := _find_variant(generator, &"chunk_0029", 0) var river_source_left := _find_variant(generator, &"chunk_0030", 0) var river_outlet_right := _find_variant(generator, &"chunk_0031", 0) var river_outlet_left := _find_variant(generator, &"chunk_0032", 0) + var river_bend_a := _find_variant(generator, &"chunk_0035", 0) + var river_bend_b := _find_variant(generator, &"chunk_0034", 0) + var river_bend_c := _find_variant(generator, &"chunk_0033", 2) + var river_bend_d := _find_variant(generator, &"chunk_0036", 0) var beach_east := _find_variant(generator, &"chunk_0002", 0) + var canonical_bend_specs := generator._river_bend_placement_specs( + Vector2i(5, 5), + 0, + ) + var rotated_bend_specs := generator._river_bend_placement_specs( + Vector2i(5, 5), + 1, + ) + _check( + ( + canonical_bend_specs.size() == 4 + and canonical_bend_specs[2]["id"] == &"chunk_0033" + and int(canonical_bend_specs[2]["turns"]) == 2 + and rotated_bend_specs.size() == 4 + and rotated_bend_specs[2]["id"] == &"chunk_0033" + and int(rotated_bend_specs[2]["turns"]) == 3 + ), + "River bend C must retain its authored half-turn at every bend rotation.", + ) _check( ( river_cap_northwest != null @@ -1412,15 +1498,21 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void: and river_edge_top != null and river_edge_variant_top != null and river_edge_variant_bottom != null + and river_edge_vertical_left != null + and river_edge_vertical_right != null and river_source_right != null and river_source_left != null and river_outlet_right != null and river_outlet_left != null + and river_bend_a != null + and river_bend_b != null + and river_bend_c != null + and river_bend_d != null and beach_east != null ), ( - "Every authored river-bank, source, outlet, and legacy-cap variant " - + "must be available." + "Every authored river-bank, bend, source, outlet, and legacy-cap " + + "variant must be available." ), ) if ( @@ -1431,10 +1523,16 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void: and river_edge_top != null and river_edge_variant_top != null and river_edge_variant_bottom != null + and river_edge_vertical_left != null + and river_edge_vertical_right != null and river_source_right != null and river_source_left != null and river_outlet_right != null and river_outlet_left != null + and river_bend_a != null + and river_bend_b != null + and river_bend_c != null + and river_bend_d != null and beach_east != null ): _check( @@ -1458,6 +1556,60 @@ func _validate_authored_rotations(generator: TerrainChunkGenerator) -> void: ), "The paired cliff source must open directly into both river banks.", ) + _check( + generator._edges_are_compatible( + river_bend_a, + TerrainChunkTopology.Edge.EAST, + river_bend_b, + TerrainChunkTopology.Edge.WEST, + ) + and generator._edges_are_compatible( + river_bend_a, + TerrainChunkTopology.Edge.SOUTH, + river_bend_c, + TerrainChunkTopology.Edge.NORTH, + ) + and generator._edges_are_compatible( + river_bend_b, + TerrainChunkTopology.Edge.SOUTH, + river_bend_d, + TerrainChunkTopology.Edge.NORTH, + ) + and generator._edges_are_compatible( + river_bend_c, + TerrainChunkTopology.Edge.EAST, + river_bend_d, + TerrainChunkTopology.Edge.WEST, + ), + "The four authored river-bend quadrants must form one continuous turn.", + ) + _check( + generator._edges_are_compatible( + river_edge_top, + TerrainChunkTopology.Edge.EAST, + river_bend_a, + TerrainChunkTopology.Edge.WEST, + ) + and generator._edges_are_compatible( + river_edge_variant_bottom, + TerrainChunkTopology.Edge.EAST, + river_bend_c, + TerrainChunkTopology.Edge.WEST, + ) + and generator._edges_are_compatible( + river_bend_c, + TerrainChunkTopology.Edge.SOUTH, + river_edge_vertical_left, + TerrainChunkTopology.Edge.NORTH, + ) + and generator._edges_are_compatible( + river_bend_d, + TerrainChunkTopology.Edge.SOUTH, + river_edge_vertical_right, + TerrainChunkTopology.Edge.NORTH, + ), + "The bend must connect both incoming and outgoing authored river banks.", + ) _check( generator._edges_are_compatible( river_edge_top, @@ -1598,8 +1750,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)) == 150, - "The current catalog must expose all 150 authored rotations.", + int(summary.get("variant_count", 0)) == 170, + "The current catalog must expose all 170 authored rotations.", ) _check( int(summary.get("solver_variant_count", 0)) diff --git a/world/generation/chunks/assets/chunk_0017.glb b/world/generation/chunks/assets/chunk_0017.glb index 89e449a..474fa97 100644 Binary files a/world/generation/chunks/assets/chunk_0017.glb and b/world/generation/chunks/assets/chunk_0017.glb differ diff --git a/world/generation/chunks/assets/chunk_0033.glb b/world/generation/chunks/assets/chunk_0033.glb new file mode 100644 index 0000000..909f7f9 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0033.glb differ diff --git a/world/generation/chunks/assets/chunk_0033.glb.import b/world/generation/chunks/assets/chunk_0033.glb.import new file mode 100644 index 0000000..6f8545a --- /dev/null +++ b/world/generation/chunks/assets/chunk_0033.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://bpxb6irv0uy0r" +path="res://.godot/imported/chunk_0033.glb-efe42677a43450655710a9221ab8eb95.scn" + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0033.glb" +dest_files=["res://.godot/imported/chunk_0033.glb-efe42677a43450655710a9221ab8eb95.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/world/generation/chunks/assets/chunk_0033_cliff_wall.png b/world/generation/chunks/assets/chunk_0033_cliff_wall.png new file mode 100644 index 0000000..3fe157f Binary files /dev/null and b/world/generation/chunks/assets/chunk_0033_cliff_wall.png differ diff --git a/world/generation/chunks/assets/chunk_0033_cliff_wall.png.import b/world/generation/chunks/assets/chunk_0033_cliff_wall.png.import new file mode 100644 index 0000000..1fea1a8 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0033_cliff_wall.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c6e67baffellv" +path.s3tc="res://.godot/imported/chunk_0033_cliff_wall.png-5a927c95df8649ebd783b1af7c54e594.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0033_cliff_wall.png-5a927c95df8649ebd783b1af7c54e594.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "fc97184f537cc23f83a731327e10c836" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0033_cliff_wall.png" +dest_files=["res://.godot/imported/chunk_0033_cliff_wall.png-5a927c95df8649ebd783b1af7c54e594.s3tc.ctex", "res://.godot/imported/chunk_0033_cliff_wall.png-5a927c95df8649ebd783b1af7c54e594.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0033_dirt.png b/world/generation/chunks/assets/chunk_0033_dirt.png new file mode 100644 index 0000000..588c8c6 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0033_dirt.png differ diff --git a/world/generation/chunks/assets/chunk_0033_dirt.png.import b/world/generation/chunks/assets/chunk_0033_dirt.png.import new file mode 100644 index 0000000..5d3f72d --- /dev/null +++ b/world/generation/chunks/assets/chunk_0033_dirt.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bdo5u7ulyf420" +path.s3tc="res://.godot/imported/chunk_0033_dirt.png-922aa321752269bafb91e9d4b7af875e.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0033_dirt.png-922aa321752269bafb91e9d4b7af875e.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "07d90b3c46a4c3d0c172bed143dc9436" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0033_dirt.png" +dest_files=["res://.godot/imported/chunk_0033_dirt.png-922aa321752269bafb91e9d4b7af875e.s3tc.ctex", "res://.godot/imported/chunk_0033_dirt.png-922aa321752269bafb91e9d4b7af875e.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0033_grass_lite.png b/world/generation/chunks/assets/chunk_0033_grass_lite.png new file mode 100644 index 0000000..52c7ccb Binary files /dev/null and b/world/generation/chunks/assets/chunk_0033_grass_lite.png differ diff --git a/world/generation/chunks/assets/chunk_0033_grass_lite.png.import b/world/generation/chunks/assets/chunk_0033_grass_lite.png.import new file mode 100644 index 0000000..04f4308 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0033_grass_lite.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://46ryou6n6ogg" +path.s3tc="res://.godot/imported/chunk_0033_grass_lite.png-a8e03cbfa4baf7cbc6f1406eb3f5d531.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0033_grass_lite.png-a8e03cbfa4baf7cbc6f1406eb3f5d531.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "4dc1ac400d85d9b3e4f43a5af0a38ed4" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0033_grass_lite.png" +dest_files=["res://.godot/imported/chunk_0033_grass_lite.png-a8e03cbfa4baf7cbc6f1406eb3f5d531.s3tc.ctex", "res://.godot/imported/chunk_0033_grass_lite.png-a8e03cbfa4baf7cbc6f1406eb3f5d531.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0034.glb b/world/generation/chunks/assets/chunk_0034.glb new file mode 100644 index 0000000..0facbc5 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0034.glb differ diff --git a/world/generation/chunks/assets/chunk_0034.glb.import b/world/generation/chunks/assets/chunk_0034.glb.import new file mode 100644 index 0000000..8f0a04c --- /dev/null +++ b/world/generation/chunks/assets/chunk_0034.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dyihbkykyskj" +path="res://.godot/imported/chunk_0034.glb-b92b8ad51734f50a55c4f2e13c2ba1dc.scn" + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0034.glb" +dest_files=["res://.godot/imported/chunk_0034.glb-b92b8ad51734f50a55c4f2e13c2ba1dc.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/world/generation/chunks/assets/chunk_0034_cliff_wall.png b/world/generation/chunks/assets/chunk_0034_cliff_wall.png new file mode 100644 index 0000000..3fe157f Binary files /dev/null and b/world/generation/chunks/assets/chunk_0034_cliff_wall.png differ diff --git a/world/generation/chunks/assets/chunk_0034_cliff_wall.png.import b/world/generation/chunks/assets/chunk_0034_cliff_wall.png.import new file mode 100644 index 0000000..0bfd461 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0034_cliff_wall.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ceu5tr7jpsl8s" +path.s3tc="res://.godot/imported/chunk_0034_cliff_wall.png-547e43ba799070ca9d5487085e0b87be.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0034_cliff_wall.png-547e43ba799070ca9d5487085e0b87be.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "fc97184f537cc23f83a731327e10c836" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0034_cliff_wall.png" +dest_files=["res://.godot/imported/chunk_0034_cliff_wall.png-547e43ba799070ca9d5487085e0b87be.s3tc.ctex", "res://.godot/imported/chunk_0034_cliff_wall.png-547e43ba799070ca9d5487085e0b87be.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0034_dirt.png b/world/generation/chunks/assets/chunk_0034_dirt.png new file mode 100644 index 0000000..588c8c6 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0034_dirt.png differ diff --git a/world/generation/chunks/assets/chunk_0034_dirt.png.import b/world/generation/chunks/assets/chunk_0034_dirt.png.import new file mode 100644 index 0000000..8a37ca8 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0034_dirt.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://brbxnlixypkxp" +path.s3tc="res://.godot/imported/chunk_0034_dirt.png-1bf0eb5903180997b50f578932bd52c6.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0034_dirt.png-1bf0eb5903180997b50f578932bd52c6.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "07d90b3c46a4c3d0c172bed143dc9436" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0034_dirt.png" +dest_files=["res://.godot/imported/chunk_0034_dirt.png-1bf0eb5903180997b50f578932bd52c6.s3tc.ctex", "res://.godot/imported/chunk_0034_dirt.png-1bf0eb5903180997b50f578932bd52c6.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0034_grass_lite.png b/world/generation/chunks/assets/chunk_0034_grass_lite.png new file mode 100644 index 0000000..52c7ccb Binary files /dev/null and b/world/generation/chunks/assets/chunk_0034_grass_lite.png differ diff --git a/world/generation/chunks/assets/chunk_0034_grass_lite.png.import b/world/generation/chunks/assets/chunk_0034_grass_lite.png.import new file mode 100644 index 0000000..8739610 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0034_grass_lite.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8crpbxki018u" +path.s3tc="res://.godot/imported/chunk_0034_grass_lite.png-d7f44fbe927d93f7021da5b9cf23444e.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0034_grass_lite.png-d7f44fbe927d93f7021da5b9cf23444e.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "4dc1ac400d85d9b3e4f43a5af0a38ed4" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0034_grass_lite.png" +dest_files=["res://.godot/imported/chunk_0034_grass_lite.png-d7f44fbe927d93f7021da5b9cf23444e.s3tc.ctex", "res://.godot/imported/chunk_0034_grass_lite.png-d7f44fbe927d93f7021da5b9cf23444e.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0035.glb b/world/generation/chunks/assets/chunk_0035.glb new file mode 100644 index 0000000..3da18d8 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0035.glb differ diff --git a/world/generation/chunks/assets/chunk_0035.glb.import b/world/generation/chunks/assets/chunk_0035.glb.import new file mode 100644 index 0000000..729725f --- /dev/null +++ b/world/generation/chunks/assets/chunk_0035.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://da8d1mejjp333" +path="res://.godot/imported/chunk_0035.glb-af3dcdae51aaba377d5b5344b50be7c7.scn" + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0035.glb" +dest_files=["res://.godot/imported/chunk_0035.glb-af3dcdae51aaba377d5b5344b50be7c7.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/world/generation/chunks/assets/chunk_0035_cliff_wall.png b/world/generation/chunks/assets/chunk_0035_cliff_wall.png new file mode 100644 index 0000000..3fe157f Binary files /dev/null and b/world/generation/chunks/assets/chunk_0035_cliff_wall.png differ diff --git a/world/generation/chunks/assets/chunk_0035_cliff_wall.png.import b/world/generation/chunks/assets/chunk_0035_cliff_wall.png.import new file mode 100644 index 0000000..356ffcb --- /dev/null +++ b/world/generation/chunks/assets/chunk_0035_cliff_wall.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dp4kpw64dmukj" +path.s3tc="res://.godot/imported/chunk_0035_cliff_wall.png-ec09ffbe6a034f8e0f0052e721831ef2.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0035_cliff_wall.png-ec09ffbe6a034f8e0f0052e721831ef2.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "fc97184f537cc23f83a731327e10c836" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0035_cliff_wall.png" +dest_files=["res://.godot/imported/chunk_0035_cliff_wall.png-ec09ffbe6a034f8e0f0052e721831ef2.s3tc.ctex", "res://.godot/imported/chunk_0035_cliff_wall.png-ec09ffbe6a034f8e0f0052e721831ef2.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0035_dirt.png b/world/generation/chunks/assets/chunk_0035_dirt.png new file mode 100644 index 0000000..588c8c6 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0035_dirt.png differ diff --git a/world/generation/chunks/assets/chunk_0035_dirt.png.import b/world/generation/chunks/assets/chunk_0035_dirt.png.import new file mode 100644 index 0000000..196b777 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0035_dirt.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dc1nrektrgqkp" +path.s3tc="res://.godot/imported/chunk_0035_dirt.png-58b1612acd4423920b9fa50fc3926b47.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0035_dirt.png-58b1612acd4423920b9fa50fc3926b47.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "07d90b3c46a4c3d0c172bed143dc9436" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0035_dirt.png" +dest_files=["res://.godot/imported/chunk_0035_dirt.png-58b1612acd4423920b9fa50fc3926b47.s3tc.ctex", "res://.godot/imported/chunk_0035_dirt.png-58b1612acd4423920b9fa50fc3926b47.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0035_grass_lite.png b/world/generation/chunks/assets/chunk_0035_grass_lite.png new file mode 100644 index 0000000..52c7ccb Binary files /dev/null and b/world/generation/chunks/assets/chunk_0035_grass_lite.png differ diff --git a/world/generation/chunks/assets/chunk_0035_grass_lite.png.import b/world/generation/chunks/assets/chunk_0035_grass_lite.png.import new file mode 100644 index 0000000..7b09849 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0035_grass_lite.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dxqphihkd5flj" +path.s3tc="res://.godot/imported/chunk_0035_grass_lite.png-502ef62d50c50e34bc377a90431a69a5.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0035_grass_lite.png-502ef62d50c50e34bc377a90431a69a5.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "4dc1ac400d85d9b3e4f43a5af0a38ed4" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0035_grass_lite.png" +dest_files=["res://.godot/imported/chunk_0035_grass_lite.png-502ef62d50c50e34bc377a90431a69a5.s3tc.ctex", "res://.godot/imported/chunk_0035_grass_lite.png-502ef62d50c50e34bc377a90431a69a5.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0036.glb b/world/generation/chunks/assets/chunk_0036.glb new file mode 100644 index 0000000..105c8cc Binary files /dev/null and b/world/generation/chunks/assets/chunk_0036.glb differ diff --git a/world/generation/chunks/assets/chunk_0036.glb.import b/world/generation/chunks/assets/chunk_0036.glb.import new file mode 100644 index 0000000..c5de4a4 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0036.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://c005rpmfnc8af" +path="res://.godot/imported/chunk_0036.glb-36b04f9c2ce7f32bcbb76f4287e5b3aa.scn" + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0036.glb" +dest_files=["res://.godot/imported/chunk_0036.glb-36b04f9c2ce7f32bcbb76f4287e5b3aa.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/world/generation/chunks/assets/chunk_0036_cliff_wall.png b/world/generation/chunks/assets/chunk_0036_cliff_wall.png new file mode 100644 index 0000000..3fe157f Binary files /dev/null and b/world/generation/chunks/assets/chunk_0036_cliff_wall.png differ diff --git a/world/generation/chunks/assets/chunk_0036_cliff_wall.png.import b/world/generation/chunks/assets/chunk_0036_cliff_wall.png.import new file mode 100644 index 0000000..8913259 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0036_cliff_wall.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://be7duf8cxv1dt" +path.s3tc="res://.godot/imported/chunk_0036_cliff_wall.png-b0aeca8dd67e5918b04f4e62418713f0.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0036_cliff_wall.png-b0aeca8dd67e5918b04f4e62418713f0.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "fc97184f537cc23f83a731327e10c836" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0036_cliff_wall.png" +dest_files=["res://.godot/imported/chunk_0036_cliff_wall.png-b0aeca8dd67e5918b04f4e62418713f0.s3tc.ctex", "res://.godot/imported/chunk_0036_cliff_wall.png-b0aeca8dd67e5918b04f4e62418713f0.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0036_dirt.png b/world/generation/chunks/assets/chunk_0036_dirt.png new file mode 100644 index 0000000..588c8c6 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0036_dirt.png differ diff --git a/world/generation/chunks/assets/chunk_0036_dirt.png.import b/world/generation/chunks/assets/chunk_0036_dirt.png.import new file mode 100644 index 0000000..56830df --- /dev/null +++ b/world/generation/chunks/assets/chunk_0036_dirt.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tb7yncykrheo" +path.s3tc="res://.godot/imported/chunk_0036_dirt.png-38c14a27c0e4c7f325f880966042443b.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0036_dirt.png-38c14a27c0e4c7f325f880966042443b.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "07d90b3c46a4c3d0c172bed143dc9436" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0036_dirt.png" +dest_files=["res://.godot/imported/chunk_0036_dirt.png-38c14a27c0e4c7f325f880966042443b.s3tc.ctex", "res://.godot/imported/chunk_0036_dirt.png-38c14a27c0e4c7f325f880966042443b.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0036_grass_lite.png b/world/generation/chunks/assets/chunk_0036_grass_lite.png new file mode 100644 index 0000000..52c7ccb Binary files /dev/null and b/world/generation/chunks/assets/chunk_0036_grass_lite.png differ diff --git a/world/generation/chunks/assets/chunk_0036_grass_lite.png.import b/world/generation/chunks/assets/chunk_0036_grass_lite.png.import new file mode 100644 index 0000000..28be931 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0036_grass_lite.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dp728huemli1l" +path.s3tc="res://.godot/imported/chunk_0036_grass_lite.png-3b0265ab9b8f49ff9ebe9e3c8c2d581c.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0036_grass_lite.png-3b0265ab9b8f49ff9ebe9e3c8c2d581c.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "4dc1ac400d85d9b3e4f43a5af0a38ed4" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0036_grass_lite.png" +dest_files=["res://.godot/imported/chunk_0036_grass_lite.png-3b0265ab9b8f49ff9ebe9e3c8c2d581c.s3tc.ctex", "res://.godot/imported/chunk_0036_grass_lite.png-3b0265ab9b8f49ff9ebe9e3c8c2d581c.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0037.glb b/world/generation/chunks/assets/chunk_0037.glb new file mode 100644 index 0000000..c02c7e7 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0037.glb differ diff --git a/world/generation/chunks/assets/chunk_0037.glb.import b/world/generation/chunks/assets/chunk_0037.glb.import new file mode 100644 index 0000000..660b46f --- /dev/null +++ b/world/generation/chunks/assets/chunk_0037.glb.import @@ -0,0 +1,45 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://cbvyhqj5lfy2h" +path="res://.godot/imported/chunk_0037.glb-6c483e5e2d770b53845b998f0cb7153d.scn" + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0037.glb" +dest_files=["res://.godot/imported/chunk_0037.glb-6c483e5e2d770b53845b998f0cb7153d.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/root_script=null +mesh_library/use_node_names_as_mesh_names=false +array_mesh/deduplicate_surfaces=true +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_name_suffixes=true +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +materials/extract=0 +materials/extract_format=0 +materials/extract_path="" +_subresources={} +gltf/naming_version=2 +gltf/embedded_image_handling=1 +gltf/texture_map_mode=1 diff --git a/world/generation/chunks/assets/chunk_0037_cliff_wall.png b/world/generation/chunks/assets/chunk_0037_cliff_wall.png new file mode 100644 index 0000000..3fe157f Binary files /dev/null and b/world/generation/chunks/assets/chunk_0037_cliff_wall.png differ diff --git a/world/generation/chunks/assets/chunk_0037_cliff_wall.png.import b/world/generation/chunks/assets/chunk_0037_cliff_wall.png.import new file mode 100644 index 0000000..57a5e84 --- /dev/null +++ b/world/generation/chunks/assets/chunk_0037_cliff_wall.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://n0eputww5tlq" +path.s3tc="res://.godot/imported/chunk_0037_cliff_wall.png-0a403a214126258c4e4c342f3ca37abc.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0037_cliff_wall.png-0a403a214126258c4e4c342f3ca37abc.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "fc97184f537cc23f83a731327e10c836" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0037_cliff_wall.png" +dest_files=["res://.godot/imported/chunk_0037_cliff_wall.png-0a403a214126258c4e4c342f3ca37abc.s3tc.ctex", "res://.godot/imported/chunk_0037_cliff_wall.png-0a403a214126258c4e4c342f3ca37abc.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0037_dirt.png b/world/generation/chunks/assets/chunk_0037_dirt.png new file mode 100644 index 0000000..588c8c6 Binary files /dev/null and b/world/generation/chunks/assets/chunk_0037_dirt.png differ diff --git a/world/generation/chunks/assets/chunk_0037_dirt.png.import b/world/generation/chunks/assets/chunk_0037_dirt.png.import new file mode 100644 index 0000000..63ee56e --- /dev/null +++ b/world/generation/chunks/assets/chunk_0037_dirt.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cie8oie0c845v" +path.s3tc="res://.godot/imported/chunk_0037_dirt.png-19715c4c1848faa763210a57f6770bc8.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0037_dirt.png-19715c4c1848faa763210a57f6770bc8.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "07d90b3c46a4c3d0c172bed143dc9436" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0037_dirt.png" +dest_files=["res://.godot/imported/chunk_0037_dirt.png-19715c4c1848faa763210a57f6770bc8.s3tc.ctex", "res://.godot/imported/chunk_0037_dirt.png-19715c4c1848faa763210a57f6770bc8.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/assets/chunk_0037_grass_lite.png b/world/generation/chunks/assets/chunk_0037_grass_lite.png new file mode 100644 index 0000000..52c7ccb Binary files /dev/null and b/world/generation/chunks/assets/chunk_0037_grass_lite.png differ diff --git a/world/generation/chunks/assets/chunk_0037_grass_lite.png.import b/world/generation/chunks/assets/chunk_0037_grass_lite.png.import new file mode 100644 index 0000000..d884d1f --- /dev/null +++ b/world/generation/chunks/assets/chunk_0037_grass_lite.png.import @@ -0,0 +1,45 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8ofl5u3qo5ku" +path.s3tc="res://.godot/imported/chunk_0037_grass_lite.png-54ca324ca08bbf565871368a2502c758.s3tc.ctex" +path.etc2="res://.godot/imported/chunk_0037_grass_lite.png-54ca324ca08bbf565871368a2502c758.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={ +"md5": "4dc1ac400d85d9b3e4f43a5af0a38ed4" +} + +[deps] + +source_file="res://world/generation/chunks/assets/chunk_0037_grass_lite.png" +dest_files=["res://.godot/imported/chunk_0037_grass_lite.png-54ca324ca08bbf565871368a2502c758.s3tc.ctex", "res://.godot/imported/chunk_0037_grass_lite.png-54ca324ca08bbf565871368a2502c758.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/world/generation/chunks/definitions/chunk_0033.tres b/world/generation/chunks/definitions/chunk_0033.tres new file mode 100644 index 0000000..f452ae0 --- /dev/null +++ b/world/generation/chunks/definitions/chunk_0033.tres @@ -0,0 +1,22 @@ +[gd_resource type="Resource" script_class="TerrainChunkDefinition" load_steps=3 format=3] + +[ext_resource type="Script" path="res://world/generation/terrain_chunk_definition.gd" id="1_definition"] +[ext_resource type="PackedScene" path="res://world/generation/chunks/assets/chunk_0033.glb" id="2_scene"] + +[resource] +script = ExtResource("1_definition") +stable_id = &"chunk_0033" +label = "river bend c" +packed_scene = ExtResource("2_scene") +primary_mesh_name = &"chunk_0033" +participates_in_base_solver = false +selection_weight = 0.1 +maximum_placements = 1 +tags = PackedStringArray("land", "walkable", "fresh_water", "river", "river_bend", "river_bend_c", "flowing") +allowed_neighbor_tags = PackedStringArray("grass") +preferred_neighbor_tags = PackedStringArray("grass", "fresh_water", "river") +must_be_interior = true +water_inlet_edges = 15 +water_outlet_edges = 15 +continuous_water_seam_edges = 15 +water_surface_polygon = PackedVector2Array(-5, -5, 5, -5, 5, 5, -5, 5) diff --git a/world/generation/chunks/definitions/chunk_0034.tres b/world/generation/chunks/definitions/chunk_0034.tres new file mode 100644 index 0000000..560b3d6 --- /dev/null +++ b/world/generation/chunks/definitions/chunk_0034.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="TerrainChunkDefinition" load_steps=3 format=3] + +[ext_resource type="Script" path="res://world/generation/terrain_chunk_definition.gd" id="1_definition"] +[ext_resource type="PackedScene" path="res://world/generation/chunks/assets/chunk_0034.glb" id="2_scene"] + +[resource] +script = ExtResource("1_definition") +stable_id = &"chunk_0034" +label = "river bend b" +packed_scene = ExtResource("2_scene") +primary_mesh_name = &"chunk_0034" +participates_in_base_solver = false +selection_weight = 0.1 +maximum_placements = 1 +tags = PackedStringArray("land", "walkable", "grass", "flat", "spawn_safe", "fresh_water", "river", "river_border", "river_bend", "river_bend_b", "flowing") +allowed_neighbor_tags = PackedStringArray("grass") +north_allowed_neighbor_tags = PackedStringArray("grass") +east_allowed_neighbor_tags = PackedStringArray("grass") +north_surface_tags = PackedStringArray("grass") +east_surface_tags = PackedStringArray("grass") +preferred_neighbor_tags = PackedStringArray("grass", "fresh_water", "river") +must_be_interior = true +water_inlet_edges = 12 +water_outlet_edges = 12 +water_surface_polygon = PackedVector2Array(2.078653, 1.417459, 0.873861, -3.316683, -0.954994, -3.086828, -2.030681, -3.440039, -3.172947, -3.869164, -4.197278, -3.878055, -5, -4.499509, -5, 5, 1.25, 5) diff --git a/world/generation/chunks/definitions/chunk_0035.tres b/world/generation/chunks/definitions/chunk_0035.tres new file mode 100644 index 0000000..1f6fca7 --- /dev/null +++ b/world/generation/chunks/definitions/chunk_0035.tres @@ -0,0 +1,23 @@ +[gd_resource type="Resource" script_class="TerrainChunkDefinition" load_steps=3 format=3] + +[ext_resource type="Script" path="res://world/generation/terrain_chunk_definition.gd" id="1_definition"] +[ext_resource type="PackedScene" path="res://world/generation/chunks/assets/chunk_0035.glb" id="2_scene"] + +[resource] +script = ExtResource("1_definition") +stable_id = &"chunk_0035" +label = "river bend a" +packed_scene = ExtResource("2_scene") +primary_mesh_name = &"chunk_0035" +participates_in_base_solver = false +selection_weight = 0.1 +maximum_placements = 1 +tags = PackedStringArray("land", "walkable", "grass", "flat", "spawn_safe", "fresh_water", "river", "river_border", "river_bend", "river_bend_a", "flowing") +allowed_neighbor_tags = PackedStringArray("grass") +north_allowed_neighbor_tags = PackedStringArray("grass") +north_surface_tags = PackedStringArray("grass") +preferred_neighbor_tags = PackedStringArray("grass", "fresh_water", "river") +must_be_interior = true +water_inlet_edges = 14 +water_outlet_edges = 14 +water_surface_polygon = PackedVector2Array(-5, -4.619923, -4.19697, -4.000163, -3.172378, -3.982254, -2.030086, -3.55834, -0.95432, -3.220759, 0.874552, -3.454032, 2.118941, -3.669504, 2.931416, -3.612123, 3.664019, -3.974483, 4.456637, -4.104719, 5, -4.619923, 5, 5, -5, 5) diff --git a/world/generation/chunks/definitions/chunk_0036.tres b/world/generation/chunks/definitions/chunk_0036.tres new file mode 100644 index 0000000..61dc809 --- /dev/null +++ b/world/generation/chunks/definitions/chunk_0036.tres @@ -0,0 +1,24 @@ +[gd_resource type="Resource" script_class="TerrainChunkDefinition" load_steps=3 format=3] + +[ext_resource type="Script" path="res://world/generation/terrain_chunk_definition.gd" id="1_definition"] +[ext_resource type="PackedScene" path="res://world/generation/chunks/assets/chunk_0036.glb" id="2_scene"] + +[resource] +script = ExtResource("1_definition") +stable_id = &"chunk_0036" +label = "river bend d" +packed_scene = ExtResource("2_scene") +primary_mesh_name = &"chunk_0036" +participates_in_base_solver = false +selection_weight = 0.1 +maximum_placements = 1 +tags = PackedStringArray("land", "walkable", "grass", "flat", "spawn_safe", "fresh_water", "river", "river_border", "river_bend", "river_bend_d", "flowing") +allowed_neighbor_tags = PackedStringArray("grass") +east_allowed_neighbor_tags = PackedStringArray("grass") +east_surface_tags = PackedStringArray("grass") +preferred_neighbor_tags = PackedStringArray("grass", "fresh_water", "river") +must_be_interior = true +water_inlet_edges = 13 +water_outlet_edges = 13 +continuous_water_seam_edges = 1 +water_surface_polygon = PackedVector2Array(-5, -5, 2.057564, -5, 2.087937, -3.582541, 2.118311, -2.165082, 2.191291, -1.52149, 2.264271, -0.877898, 2.078653, 1.417459, 2.734523, 3.269125, 4.489859, 5, -5, 5) diff --git a/world/generation/chunks/definitions/chunk_0037.tres b/world/generation/chunks/definitions/chunk_0037.tres new file mode 100644 index 0000000..e1198f6 --- /dev/null +++ b/world/generation/chunks/definitions/chunk_0037.tres @@ -0,0 +1,22 @@ +[gd_resource type="Resource" script_class="TerrainChunkDefinition" load_steps=3 format=3] + +[ext_resource type="Script" path="res://world/generation/terrain_chunk_definition.gd" id="1_definition"] +[ext_resource type="PackedScene" path="res://world/generation/chunks/assets/chunk_0037.glb" id="2_scene"] + +[resource] +script = ExtResource("1_definition") +stable_id = &"chunk_0037" +label = "lake edge variant" +packed_scene = ExtResource("2_scene") +primary_mesh_name = &"chunk_0037" +participates_in_base_solver = false +selection_weight = 0.2 +maximum_placements = 16 +tags = PackedStringArray("land", "walkable", "grass", "flat", "spawn_safe", "fresh_water", "lake", "lake_border") +allowed_neighbor_tags = PackedStringArray("grass") +preferred_neighbor_tags = PackedStringArray("grass", "fresh_water", "lake") +must_be_interior = true +water_inlet_edges = 7 +water_outlet_edges = 7 +water_surface_size = Vector2(6.3, 10) +water_surface_offset = Vector2(1.85, 0) diff --git a/world/generation/chunks/terrain_chunk_catalog.tres b/world/generation/chunks/terrain_chunk_catalog.tres index 51b17d3..992e847 100644 --- a/world/generation/chunks/terrain_chunk_catalog.tres +++ b/world/generation/chunks/terrain_chunk_catalog.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" script_class="TerrainChunkCatalog" load_steps=42 format=3] +[gd_resource type="Resource" script_class="TerrainChunkCatalog" load_steps=47 format=3] [ext_resource type="Script" path="res://world/generation/terrain_chunk_catalog.gd" id="1_catalog"] [ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0000.tres" id="2_grass"] @@ -37,6 +37,11 @@ [ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0030.tres" id="39_river_source_left"] [ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0031.tres" id="40_river_outlet_right"] [ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0032.tres" id="41_river_outlet_left"] +[ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0033.tres" id="42_river_bend_c"] +[ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0034.tres" id="43_river_bend_b"] +[ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0035.tres" id="44_river_bend_a"] +[ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0036.tres" id="45_river_bend_d"] +[ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_0037.tres" id="46_lake_edge_variant"] [ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_9999.tres" id="21_cliff_sea_transition_right"] [ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_9998.tres" id="22_cliff_sea_transition_left"] [ext_resource type="Resource" path="res://world/generation/chunks/definitions/chunk_9997.tres" id="23_cliff_beach_transition_right"] @@ -45,4 +50,4 @@ [resource] script = ExtResource("1_catalog") chunk_size = 10.0 -definitions = Array[ExtResource("7_definition_script")]([ExtResource("2_grass"), ExtResource("3_sand"), ExtResource("4_beach"), ExtResource("5_stream"), ExtResource("20_stream_variant"), ExtResource("6_pond"), ExtResource("25_lake_edge"), ExtResource("26_lake_corner"), ExtResource("27_lake_fill"), ExtResource("28_lake_diagonal"), ExtResource("29_lake_narrow"), ExtResource("30_lake_regular_to_narrow"), ExtResource("31_lake_narrow_to_regular"), ExtResource("32_river_edge"), ExtResource("33_river_edge_variant"), ExtResource("38_river_source_right"), ExtResource("39_river_source_left"), ExtResource("40_river_outlet_right"), ExtResource("41_river_outlet_left"), ExtResource("34_river_cap"), ExtResource("9_grass_ocean_edge"), ExtResource("10_grass_beach_transition"), ExtResource("11_grass_ocean_corner"), ExtResource("12_beach_ocean_corner"), ExtResource("17_grass_sand_diagonal"), ExtResource("13_cliff_top"), ExtResource("14_cliff_corner"), ExtResource("15_cliff_edge"), ExtResource("16_cliff_ramp"), ExtResource("35_cliff_third_tier_edge"), ExtResource("36_cliff_third_tier_corner"), ExtResource("37_cliff_third_tier_top"), ExtResource("18_cliff_sea_edge"), ExtResource("19_cliff_sea_corner"), ExtResource("21_cliff_sea_transition_right"), ExtResource("22_cliff_sea_transition_left"), ExtResource("23_cliff_beach_transition_right"), ExtResource("24_cliff_beach_transition_left"), ExtResource("8_spawn")]) +definitions = Array[ExtResource("7_definition_script")]([ExtResource("2_grass"), ExtResource("3_sand"), ExtResource("4_beach"), ExtResource("5_stream"), ExtResource("20_stream_variant"), ExtResource("6_pond"), ExtResource("25_lake_edge"), ExtResource("46_lake_edge_variant"), ExtResource("26_lake_corner"), ExtResource("27_lake_fill"), ExtResource("28_lake_diagonal"), ExtResource("29_lake_narrow"), ExtResource("30_lake_regular_to_narrow"), ExtResource("31_lake_narrow_to_regular"), ExtResource("32_river_edge"), ExtResource("33_river_edge_variant"), ExtResource("38_river_source_right"), ExtResource("39_river_source_left"), ExtResource("40_river_outlet_right"), ExtResource("41_river_outlet_left"), ExtResource("42_river_bend_c"), ExtResource("43_river_bend_b"), ExtResource("44_river_bend_a"), ExtResource("45_river_bend_d"), ExtResource("34_river_cap"), ExtResource("9_grass_ocean_edge"), ExtResource("10_grass_beach_transition"), ExtResource("11_grass_ocean_corner"), ExtResource("12_beach_ocean_corner"), ExtResource("17_grass_sand_diagonal"), ExtResource("13_cliff_top"), ExtResource("14_cliff_corner"), ExtResource("15_cliff_edge"), ExtResource("16_cliff_ramp"), ExtResource("35_cliff_third_tier_edge"), ExtResource("36_cliff_third_tier_corner"), ExtResource("37_cliff_third_tier_top"), ExtResource("18_cliff_sea_edge"), ExtResource("19_cliff_sea_corner"), ExtResource("21_cliff_sea_transition_right"), ExtResource("22_cliff_sea_transition_left"), ExtResource("23_cliff_beach_transition_right"), ExtResource("24_cliff_beach_transition_left"), ExtResource("8_spawn")]) diff --git a/world/generation/terrain_chunk_catalog.gd b/world/generation/terrain_chunk_catalog.gd index 40004db..3f1b374 100644 --- a/world/generation/terrain_chunk_catalog.gd +++ b/world/generation/terrain_chunk_catalog.gd @@ -69,6 +69,19 @@ func validation_errors() -> PackedStringArray: % definition.stable_id ) var has_fresh_water := "fresh_water" in definition.tags + var water_connector_edges := ( + definition.water_inlet_edges | definition.water_outlet_edges + ) + if ( + definition.continuous_water_seam_edges + & ~water_connector_edges + ) != 0: + errors.append( + ( + "%s relaxes a continuous-water seam on an edge without " + + "a water connector." + ) % definition.stable_id + ) var has_rectangular_water_footprint := ( definition.water_surface_size.x > 0.0 and definition.water_surface_size.y > 0.0 diff --git a/world/generation/terrain_chunk_definition.gd b/world/generation/terrain_chunk_definition.gd index 9f33e34..dcbceca 100644 --- a/world/generation/terrain_chunk_definition.gd +++ b/world/generation/terrain_chunk_definition.gd @@ -92,6 +92,12 @@ var edge_profile_tolerance_override := 0.0 @export_flags("North", "East", "South", "West") var buried_cliff_seam_edges := 0 @export_flags("North", "East", "South", "West") var water_inlet_edges := 0 @export_flags("North", "East", "South", "West") var water_outlet_edges := 0 +## Authored multi-cell water assemblies may deliberately carry a broad, +## continuous channel across a seam whose bank control points do not match +## one-for-one. These edges relax only the height-profile comparison; both +## neighboring edges must still expose compatible water connectors. +@export_flags("North", "East", "South", "West") +var continuous_water_seam_edges := 0 ## Optional generated water footprint in the chunk's unrotated local X/Z plane. ## Zero means this chunk contributes no standalone water surface. @export var water_surface_size := Vector2.ZERO diff --git a/world/generation/terrain_chunk_generator.gd b/world/generation/terrain_chunk_generator.gd index cc49494..1098caf 100644 --- a/world/generation/terrain_chunk_generator.gd +++ b/world/generation/terrain_chunk_generator.gd @@ -38,6 +38,7 @@ const MAX_PACKED_SOLVER_VARIANTS := 62 @export_group("Freshwater Lake Feature") @export var lake_feature_enabled := false @export var lake_edge_chunk_id: StringName = &"chunk_0017" +@export var lake_edge_variant_chunk_id: StringName = &"chunk_0037" @export var lake_corner_chunk_id: StringName = &"chunk_0018" @export var lake_fill_chunk_id: StringName = &"chunk_0019" @export var lake_diagonal_chunk_id: StringName = &"chunk_0020" @@ -57,6 +58,10 @@ const MAX_PACKED_SOLVER_VARIANTS := 62 @export var river_source_left_chunk_id: StringName = &"chunk_0030" @export var river_outlet_right_chunk_id: StringName = &"chunk_0031" @export var river_outlet_left_chunk_id: StringName = &"chunk_0032" +@export var river_bend_c_chunk_id: StringName = &"chunk_0033" +@export var river_bend_b_chunk_id: StringName = &"chunk_0034" +@export var river_bend_a_chunk_id: StringName = &"chunk_0035" +@export var river_bend_d_chunk_id: StringName = &"chunk_0036" @export_range(5, 8, 1) var river_minimum_length := 5 @export_range(5, 8, 1) var river_maximum_length := 5 @export_group("") @@ -136,9 +141,13 @@ var _lake_feature_reserved_grass_indices: Dictionary[int, bool] = {} var _river_feature_origin := Vector2i(-1, -1) var _river_feature_footprint_size := Vector2i.ZERO var _river_feature_flow_direction := Vector2i.ZERO +var _river_feature_outlet_direction := Vector2i.ZERO var _river_feature_reserved_grass_indices: Dictionary[int, bool] = {} var _river_feature_candidate_order: Array[Dictionary] = [] var _river_feature_candidate_index := -1 +var _river_feature_placements: Array[Dictionary] = [] +var _river_feature_coordinates: Dictionary[Vector2i, bool] = {} +var _river_feature_source_coordinates: Array[Vector2i] = [] var _stacked_elevated_placements: Array[Dictionary] = [] @@ -1460,9 +1469,8 @@ func _elevated_feature_overlaps_river( center: Vector2i, clearance_radius: int, ) -> bool: - if _river_feature_origin.x < 0: + if _river_feature_coordinates.is_empty(): return false - var river_end := _river_feature_origin + _river_feature_footprint_size for row: int in range( center.y - clearance_radius, center.y + clearance_radius + 1, @@ -1471,12 +1479,13 @@ func _elevated_feature_overlaps_river( center.x - clearance_radius, center.x + clearance_radius + 1, ): - if ( - column >= _river_feature_origin.x - and column < river_end.x - and row >= _river_feature_origin.y - and row < river_end.y - ): + var coordinate := Vector2i(column, row) + if _river_feature_coordinates.has(coordinate): + return true + if not _coordinate_is_inside_grid(coordinate): + continue + var index := coordinate.y * grid_size.x + coordinate.x + if _river_feature_reserved_grass_indices.has(index): return true return false @@ -1510,6 +1519,9 @@ func _prepare_lake_feature_region(report_no_room_error := true) -> bool: if not lake_feature_enabled: return true var edge_definition := catalog.definition_for_id(lake_edge_chunk_id) + var edge_variant_definition := catalog.definition_for_id( + lake_edge_variant_chunk_id + ) var corner_definition := catalog.definition_for_id(lake_corner_chunk_id) var fill_definition := catalog.definition_for_id(lake_fill_chunk_id) var diagonal_definition := catalog.definition_for_id(lake_diagonal_chunk_id) @@ -1520,11 +1532,18 @@ func _prepare_lake_feature_region(report_no_room_error := true) -> bool: var narrow_to_regular_definition := catalog.definition_for_id( lake_narrow_to_regular_chunk_id ) - if edge_definition == null or corner_definition == null: - push_error("Lake feature references missing edge or corner chunks.") + if ( + edge_definition == null + or edge_variant_definition == null + or corner_definition == null + ): + push_error( + "Lake feature references missing edge, edge variant, or corner chunks." + ) return false if ( edge_definition.participates_in_base_solver + or edge_variant_definition.participates_in_base_solver or corner_definition.participates_in_base_solver or ( fill_definition != null @@ -1677,9 +1696,13 @@ func _prepare_river_feature_region(report_no_room_error := true) -> bool: _river_feature_origin = Vector2i(-1, -1) _river_feature_footprint_size = Vector2i.ZERO _river_feature_flow_direction = Vector2i.ZERO + _river_feature_outlet_direction = Vector2i.ZERO _river_feature_reserved_grass_indices.clear() _river_feature_candidate_order.clear() _river_feature_candidate_index = -1 + _river_feature_placements.clear() + _river_feature_coordinates.clear() + _river_feature_source_coordinates.clear() if not river_feature_enabled: return true for stable_id: StringName in [ @@ -1689,6 +1712,10 @@ func _prepare_river_feature_region(report_no_room_error := true) -> bool: river_source_left_chunk_id, river_outlet_right_chunk_id, river_outlet_left_chunk_id, + river_bend_a_chunk_id, + river_bend_b_chunk_id, + river_bend_c_chunk_id, + river_bend_d_chunk_id, ]: var definition := catalog.definition_for_id(stable_id) if definition == null: @@ -1750,62 +1777,56 @@ func _select_river_feature_region(candidate_index: int) -> bool: ): return false var selected: Dictionary = _river_feature_candidate_order[candidate_index] + if not _river_feature_candidate_is_valid(selected): + return false var origin: Vector2i = selected.get("origin", Vector2i(-1, -1)) var footprint_size: Vector2i = selected.get("size", Vector2i.ZERO) var flow_direction: Vector2i = selected.get( "flow_direction", Vector2i.ZERO, ) - var source_coordinates := _river_source_coordinates( - origin, - footprint_size, - flow_direction, + var outlet_direction: Vector2i = selected.get( + "outlet_direction", + Vector2i.ZERO, ) - var source_lookup: Dictionary[Vector2i, bool] = {} - var source_exit_lookup: Dictionary[Vector2i, bool] = {} - for coordinate: Vector2i in source_coordinates: - source_lookup[coordinate] = true - source_exit_lookup[coordinate + flow_direction] = true - for row: int in range(origin.y, origin.y + footprint_size.y): - for column: int in range(origin.x, origin.x + footprint_size.x): - var coordinate := Vector2i(column, row) - var index := row * grid_size.x + column - if ( - ( - _elevated_feature_reserved_grass_indices.has(index) - and not source_lookup.has(coordinate) - and not source_exit_lookup.has(coordinate) - ) - or _lake_feature_reserved_grass_indices.has(index) - ): - return false - for coordinate: Vector2i in source_coordinates: - var index := coordinate.y * grid_size.x + coordinate.x - if not _elevated_feature_reserved_grass_indices.has(index): - return false + var source_coordinates: Array[Vector2i] = [] + source_coordinates.assign(selected.get("source_coordinates", [])) + var placements: Array[Dictionary] = [] + placements.assign(selected.get("placements", [])) + var coordinates: Array[Vector2i] = [] + coordinates.assign(selected.get("coordinates", [])) _river_feature_candidate_index = candidate_index _river_feature_origin = origin _river_feature_footprint_size = footprint_size _river_feature_flow_direction = flow_direction + _river_feature_outlet_direction = outlet_direction + _river_feature_source_coordinates.assign(source_coordinates) + _river_feature_placements.assign(placements) + _river_feature_coordinates.clear() + for coordinate: Vector2i in coordinates: + _river_feature_coordinates[coordinate] = true _river_feature_reserved_grass_indices.clear() - var river_end := _river_feature_origin + _river_feature_footprint_size - for row: int in range( - _river_feature_origin.y - RIVER_FEATURE_CLEARANCE, - river_end.y + RIVER_FEATURE_CLEARANCE, - ): - for column: int in range( - _river_feature_origin.x - RIVER_FEATURE_CLEARANCE, - river_end.x + RIVER_FEATURE_CLEARANCE, + for river_coordinate: Vector2i in coordinates: + for row_offset: int in range( + -RIVER_FEATURE_CLEARANCE, + RIVER_FEATURE_CLEARANCE + 1, ): - var coordinate := Vector2i(column, row) - if ( - not _coordinate_is_inside_grid(coordinate) - or _coordinate_is_on_boundary(coordinate) + for column_offset: int in range( + -RIVER_FEATURE_CLEARANCE, + RIVER_FEATURE_CLEARANCE + 1, ): - continue - _river_feature_reserved_grass_indices[ - row * grid_size.x + column - ] = true + var coordinate := ( + river_coordinate + + Vector2i(column_offset, row_offset) + ) + if ( + not _coordinate_is_inside_grid(coordinate) + or _coordinate_is_on_boundary(coordinate) + ): + continue + _river_feature_reserved_grass_indices[ + coordinate.y * grid_size.x + coordinate.x + ] = true return true @@ -1823,129 +1844,614 @@ func _river_feature_candidates( ] for flow_direction: Vector2i in directions: for cross_offset: int in [-1, 0]: - var footprint_size := ( - Vector2i(length, 2) - if flow_direction.x != 0 - else Vector2i(2, length) - ) - var origin := Vector2i.ZERO - match flow_direction: - Vector2i.RIGHT: - origin = Vector2i( - _elevated_feature_center.x + ELEVATED_FEATURE_RADIUS, - _elevated_feature_center.y + cross_offset, - ) - Vector2i.LEFT: - origin = Vector2i( - _elevated_feature_center.x - - ELEVATED_FEATURE_RADIUS - - length - + 1, - _elevated_feature_center.y + cross_offset, - ) - Vector2i.DOWN: - origin = Vector2i( - _elevated_feature_center.x + cross_offset, - _elevated_feature_center.y + ELEVATED_FEATURE_RADIUS, - ) - Vector2i.UP: - origin = Vector2i( - _elevated_feature_center.x + cross_offset, - _elevated_feature_center.y - - ELEVATED_FEATURE_RADIUS - - length - + 1, - ) - if _river_feature_candidate_is_valid( - origin, - footprint_size, + var source_coordinates := _river_source_pair_for_direction( flow_direction, - ): - result.append({ - "origin": origin, - "size": footprint_size, - "flow_direction": flow_direction, - }) + cross_offset, + ) + for bend_distance: int in range(2, maxi(3, length - 1)): + var target_entry: Array[Vector2i] = [] + for coordinate: Vector2i in source_coordinates: + target_entry.append( + coordinate + flow_direction * bend_distance + ) + for bend_turns: int in 4: + var sides := _river_bend_sides(bend_turns) + for entry_index: int in 2: + var entry_side: Dictionary = sides[entry_index] + if ( + entry_side.get("normal", Vector2i.ZERO) + != -flow_direction + ): + continue + var exit_side: Dictionary = sides[1 - entry_index] + var entry_offsets: Array[Vector2i] = [] + entry_offsets.assign(entry_side.get("offsets", [])) + var bend_origin := _river_pair_translation( + target_entry, + entry_offsets, + ) + if bend_origin.x == -1000000: + continue + var exit_offsets: Array[Vector2i] = [] + exit_offsets.assign(exit_side.get("offsets", [])) + var exit_coordinates: Array[Vector2i] = [] + for offset: Vector2i in exit_offsets: + exit_coordinates.append(bend_origin + offset) + var outlet_direction: Vector2i = exit_side.get( + "normal", + Vector2i.ZERO, + ) + var outlet_distance := _river_distance_to_boundary( + exit_coordinates, + outlet_direction, + ) + if ( + outlet_distance < 2 + or bend_distance + outlet_distance + 2 < length + ): + continue + var candidate := _build_river_feature_candidate( + source_coordinates, + flow_direction, + bend_origin, + bend_turns, + bend_distance, + exit_coordinates, + outlet_direction, + outlet_distance, + ) + if _river_feature_candidate_is_valid(candidate): + result.append(candidate) return result func _river_feature_candidate_is_valid( - origin: Vector2i, - footprint_size: Vector2i, - flow_direction: Vector2i, + candidate: Dictionary, ) -> bool: - var river_end := origin + footprint_size - var boundary_clearance := RIVER_FEATURE_CLEARANCE + 1 - if flow_direction.x != 0: - if ( - origin.y < boundary_clearance - or river_end.y > grid_size.y - boundary_clearance - ): - return false - if ( - flow_direction == Vector2i.RIGHT - and river_end.x != grid_size.x - ) or ( - flow_direction == Vector2i.LEFT - and origin.x != 0 - ): - return false - else: - if ( - origin.x < boundary_clearance - or river_end.x > grid_size.x - boundary_clearance - ): - return false - if ( - flow_direction == Vector2i.DOWN - and river_end.y != grid_size.y - ) or ( - flow_direction == Vector2i.UP - and origin.y != 0 - ): - return false + if candidate.is_empty(): + return false + var flow_direction: Vector2i = candidate.get( + "flow_direction", + Vector2i.ZERO, + ) + var outlet_direction: Vector2i = candidate.get( + "outlet_direction", + Vector2i.ZERO, + ) + if ( + flow_direction == Vector2i.ZERO + or outlet_direction == Vector2i.ZERO + or ( + flow_direction.x * outlet_direction.x + + flow_direction.y * outlet_direction.y + ) != 0 + ): + return false + var coordinates: Array[Vector2i] = [] + coordinates.assign(candidate.get("coordinates", [])) + var source_coordinates: Array[Vector2i] = [] + source_coordinates.assign(candidate.get("source_coordinates", [])) + var outlet_coordinates: Array[Vector2i] = [] + outlet_coordinates.assign(candidate.get("outlet_coordinates", [])) + if ( + coordinates.is_empty() + or source_coordinates.size() != 2 + or outlet_coordinates.size() != 2 + ): + return false var center := Vector2i(grid_size.x / 2, grid_size.y / 2) var source_lookup: Dictionary[Vector2i, bool] = {} var source_exit_lookup: Dictionary[Vector2i, bool] = {} - for coordinate: Vector2i in _river_source_coordinates( - origin, - footprint_size, - flow_direction, - ): + var outlet_lookup: Dictionary[Vector2i, bool] = {} + var outlet_approach_lookup: Dictionary[Vector2i, bool] = {} + for coordinate: Vector2i in source_coordinates: source_lookup[coordinate] = true source_exit_lookup[coordinate + flow_direction] = true - if source_lookup.size() != 2: - return false - for row: int in range(origin.y, river_end.y): - for column: int in range(origin.x, river_end.x): - var coordinate := Vector2i(column, row) - var index := row * grid_size.x + column - var center_distance := ( - absi(coordinate.x - center.x) - + absi(coordinate.y - center.y) + for coordinate: Vector2i in outlet_coordinates: + outlet_lookup[coordinate] = true + outlet_approach_lookup[coordinate - outlet_direction] = true + var coordinate_lookup: Dictionary[Vector2i, bool] = {} + for coordinate: Vector2i in coordinates: + if not _coordinate_is_inside_grid(coordinate): + return false + if coordinate_lookup.has(coordinate): + return false + var boundary_distance := _distance_from_map_boundary(coordinate) + if ( + boundary_distance == 0 + and not outlet_lookup.has(coordinate) + ): + return false + if ( + boundary_distance == 1 + and not outlet_approach_lookup.has(coordinate) + ): + return false + coordinate_lookup[coordinate] = true + var index := coordinate.y * grid_size.x + coordinate.x + var center_distance := ( + absi(coordinate.x - center.x) + + absi(coordinate.y - center.y) + ) + if ( + center_distance <= 1 + or _lake_feature_reserved_grass_indices.has(index) + or ( + _elevated_feature_reserved_grass_indices.has(index) + and not source_lookup.has(coordinate) + and not source_exit_lookup.has(coordinate) ) - if ( - center_distance <= 1 - or _lake_feature_reserved_grass_indices.has(index) - or ( - _elevated_feature_reserved_grass_indices.has(index) - and not source_lookup.has(coordinate) - and not source_exit_lookup.has(coordinate) - ) - ): - return false + ): + return false for coordinate: Vector2i in source_lookup: var index := coordinate.y * grid_size.x + coordinate.x if not _elevated_feature_reserved_grass_indices.has(index): return false + for coordinate: Vector2i in outlet_coordinates: + if ( + not _coordinate_is_on_boundary(coordinate) + or _coordinate_is_inside_grid(coordinate + outlet_direction) + ): + return false + var ordered_outlet := _river_sorted_pair( + outlet_coordinates, + outlet_direction, + ) + var tangent := ( + Vector2i.DOWN + if outlet_direction.x != 0 + else Vector2i.RIGHT + ) + for beach_coordinate: Vector2i in [ + ordered_outlet[0] - tangent, + ordered_outlet[1] + tangent, + ]: + if ( + not _coordinate_is_inside_grid(beach_coordinate) + or not _coordinate_is_on_boundary(beach_coordinate) + or coordinate_lookup.has(beach_coordinate) + ): + return false return true +func _river_source_pair_for_direction( + flow_direction: Vector2i, + cross_offset: int, +) -> Array[Vector2i]: + match flow_direction: + Vector2i.RIGHT: + return [ + Vector2i( + _elevated_feature_center.x + ELEVATED_FEATURE_RADIUS, + _elevated_feature_center.y + cross_offset, + ), + Vector2i( + _elevated_feature_center.x + ELEVATED_FEATURE_RADIUS, + _elevated_feature_center.y + cross_offset + 1, + ), + ] + Vector2i.LEFT: + return [ + Vector2i( + _elevated_feature_center.x - ELEVATED_FEATURE_RADIUS, + _elevated_feature_center.y + cross_offset, + ), + Vector2i( + _elevated_feature_center.x - ELEVATED_FEATURE_RADIUS, + _elevated_feature_center.y + cross_offset + 1, + ), + ] + Vector2i.DOWN: + return [ + Vector2i( + _elevated_feature_center.x + cross_offset, + _elevated_feature_center.y + ELEVATED_FEATURE_RADIUS, + ), + Vector2i( + _elevated_feature_center.x + cross_offset + 1, + _elevated_feature_center.y + ELEVATED_FEATURE_RADIUS, + ), + ] + Vector2i.UP: + return [ + Vector2i( + _elevated_feature_center.x + cross_offset, + _elevated_feature_center.y - ELEVATED_FEATURE_RADIUS, + ), + Vector2i( + _elevated_feature_center.x + cross_offset + 1, + _elevated_feature_center.y - ELEVATED_FEATURE_RADIUS, + ), + ] + return [] + + +func _river_bend_sides(quarter_turns: int) -> Array[Dictionary]: + var west_offsets: Array[Vector2i] = [Vector2i(0, 0), Vector2i(0, 1)] + var south_offsets: Array[Vector2i] = [Vector2i(0, 1), Vector2i(1, 1)] + return [ + { + "normal": _rotate_grid_direction(Vector2i.LEFT, quarter_turns), + "offsets": _rotate_river_bend_offsets( + west_offsets, + quarter_turns, + ), + }, + { + "normal": _rotate_grid_direction(Vector2i.DOWN, quarter_turns), + "offsets": _rotate_river_bend_offsets( + south_offsets, + quarter_turns, + ), + }, + ] + + +func _rotate_river_bend_offsets( + offsets: Array[Vector2i], + quarter_turns: int, +) -> Array[Vector2i]: + var result: Array[Vector2i] = [] + for offset: Vector2i in offsets: + var rotated := offset + for _turn: int in posmod(quarter_turns, 4): + rotated = Vector2i(rotated.y, 1 - rotated.x) + result.append(rotated) + return result + + +func _rotate_grid_direction( + direction: Vector2i, + quarter_turns: int, +) -> Vector2i: + var result := direction + for _turn: int in posmod(quarter_turns, 4): + result = Vector2i(result.y, -result.x) + return result + + +func _river_pair_translation( + target_coordinates: Array[Vector2i], + local_offsets: Array[Vector2i], +) -> Vector2i: + if target_coordinates.size() != 2 or local_offsets.size() != 2: + return Vector2i(-1000000, -1000000) + for reversed_offsets: bool in [false, true]: + var first_offset := local_offsets[1 if reversed_offsets else 0] + var second_offset := local_offsets[0 if reversed_offsets else 1] + var origin := target_coordinates[0] - first_offset + if origin + second_offset == target_coordinates[1]: + return origin + return Vector2i(-1000000, -1000000) + + +func _river_distance_to_boundary( + pair: Array[Vector2i], + direction: Vector2i, +) -> int: + if pair.size() != 2: + return -1 + match direction: + Vector2i.RIGHT: + return grid_size.x - 1 - pair[0].x + Vector2i.LEFT: + return pair[0].x + Vector2i.DOWN: + return grid_size.y - 1 - pair[0].y + Vector2i.UP: + return pair[0].y + return -1 + + +func _build_river_feature_candidate( + source_coordinates: Array[Vector2i], + flow_direction: Vector2i, + bend_origin: Vector2i, + bend_turns: int, + bend_distance: int, + exit_coordinates: Array[Vector2i], + outlet_direction: Vector2i, + outlet_distance: int, +) -> Dictionary: + var placements: Array[Dictionary] = [] + placements.append_array( + _river_endpoint_pair_specs( + source_coordinates, + flow_direction, + true, + ) + ) + var phase := posmod( + generation_seed + + source_coordinates[0].x + + source_coordinates[0].y + + bend_origin.x + + bend_origin.y, + 2, + ) + var station_index := 0 + for step: int in range(1, bend_distance): + var pair: Array[Vector2i] = [] + for coordinate: Vector2i in source_coordinates: + pair.append(coordinate + flow_direction * step) + placements.append_array( + _river_edge_pair_specs( + pair, + flow_direction, + phase + station_index, + ) + ) + station_index += 1 + placements.append_array( + _river_bend_placement_specs(bend_origin, bend_turns) + ) + for step: int in range(1, outlet_distance): + var pair: Array[Vector2i] = [] + for coordinate: Vector2i in exit_coordinates: + pair.append(coordinate + outlet_direction * step) + placements.append_array( + _river_edge_pair_specs( + pair, + outlet_direction, + phase + station_index, + ) + ) + station_index += 1 + var outlet_coordinates: Array[Vector2i] = [] + for coordinate: Vector2i in exit_coordinates: + outlet_coordinates.append( + coordinate + outlet_direction * outlet_distance + ) + placements.append_array( + _river_endpoint_pair_specs( + outlet_coordinates, + outlet_direction, + false, + ) + ) + var coordinates: Array[Vector2i] = [] + var minimum := Vector2i(1000000, 1000000) + var maximum := Vector2i(-1000000, -1000000) + for spec: Dictionary in placements: + var coordinate := spec.get("coordinate", Vector2i(-1, -1)) as Vector2i + coordinates.append(coordinate) + minimum.x = mini(minimum.x, coordinate.x) + minimum.y = mini(minimum.y, coordinate.y) + maximum.x = maxi(maximum.x, coordinate.x) + maximum.y = maxi(maximum.y, coordinate.y) + return { + "origin": minimum, + "size": maximum - minimum + Vector2i.ONE, + "flow_direction": flow_direction, + "outlet_direction": outlet_direction, + "source_coordinates": source_coordinates.duplicate(), + "outlet_coordinates": outlet_coordinates, + "coordinates": coordinates, + "placements": placements, + "bend_origin": bend_origin, + "bend_turns": bend_turns, + } + + +func _river_endpoint_pair_specs( + pair: Array[Vector2i], + flow_direction: Vector2i, + is_source: bool, +) -> Array[Dictionary]: + var ordered := _river_sorted_pair(pair, flow_direction) + if ordered.size() != 2: + return [] + var result: Array[Dictionary] = [] + match flow_direction: + Vector2i.RIGHT: + result.assign([ + { + "coordinate": ordered[0], + "id": ( + river_source_right_chunk_id + if is_source + else river_outlet_right_chunk_id + ), + "turns": 0, + }, + { + "coordinate": ordered[1], + "id": ( + river_source_left_chunk_id + if is_source + else river_outlet_left_chunk_id + ), + "turns": 0, + }, + ]) + Vector2i.LEFT: + result.assign([ + { + "coordinate": ordered[0], + "id": ( + river_source_left_chunk_id + if is_source + else river_outlet_left_chunk_id + ), + "turns": 2, + }, + { + "coordinate": ordered[1], + "id": ( + river_source_right_chunk_id + if is_source + else river_outlet_right_chunk_id + ), + "turns": 2, + }, + ]) + Vector2i.DOWN: + result.assign([ + { + "coordinate": ordered[0], + "id": ( + river_source_left_chunk_id + if is_source + else river_outlet_left_chunk_id + ), + "turns": 3, + }, + { + "coordinate": ordered[1], + "id": ( + river_source_right_chunk_id + if is_source + else river_outlet_right_chunk_id + ), + "turns": 3, + }, + ]) + Vector2i.UP: + result.assign([ + { + "coordinate": ordered[0], + "id": ( + river_source_right_chunk_id + if is_source + else river_outlet_right_chunk_id + ), + "turns": 1, + }, + { + "coordinate": ordered[1], + "id": ( + river_source_left_chunk_id + if is_source + else river_outlet_left_chunk_id + ), + "turns": 1, + }, + ]) + return result + + +func _river_edge_pair_specs( + pair: Array[Vector2i], + flow_direction: Vector2i, + phase: int, +) -> Array[Dictionary]: + var ordered := _river_sorted_pair(pair, flow_direction) + if ordered.size() != 2: + return [] + var edge_ids: Array[StringName] = [ + river_edge_chunk_id, + river_edge_variant_chunk_id, + ] + var first_index := posmod(phase, edge_ids.size()) + var first_turns := 0 if flow_direction.x != 0 else 1 + var second_turns := 2 if flow_direction.x != 0 else 3 + return [ + { + "coordinate": ordered[0], + "id": edge_ids[first_index], + "turns": first_turns, + }, + { + "coordinate": ordered[1], + "id": edge_ids[posmod(first_index + 1, edge_ids.size())], + "turns": second_turns, + }, + ] + + +func _river_bend_placement_specs( + bend_origin: Vector2i, + quarter_turns: int, +) -> Array[Dictionary]: + var canonical: Array[Dictionary] = [ + { + "offset": Vector2i(0, 0), + "id": river_bend_a_chunk_id, + "base_turns": 0, + }, + { + "offset": Vector2i(1, 0), + "id": river_bend_b_chunk_id, + "base_turns": 0, + }, + { + "offset": Vector2i(0, 1), + "id": river_bend_c_chunk_id, + "base_turns": 2, + }, + { + "offset": Vector2i(1, 1), + "id": river_bend_d_chunk_id, + "base_turns": 0, + }, + ] + var result: Array[Dictionary] = [] + for canonical_spec: Dictionary in canonical: + var offsets: Array[Vector2i] = [ + canonical_spec["offset"] as Vector2i, + ] + var rotated_offsets := _rotate_river_bend_offsets( + offsets, + quarter_turns, + ) + result.append({ + "coordinate": bend_origin + rotated_offsets[0], + "id": canonical_spec["id"], + "turns": posmod( + int(canonical_spec["base_turns"]) + quarter_turns, + 4, + ), + }) + return result + + +func _river_sorted_pair( + pair: Array[Vector2i], + flow_direction: Vector2i, +) -> Array[Vector2i]: + var result: Array[Vector2i] = [] + result.assign(pair) + if result.size() != 2: + return result + var swap := false + if flow_direction.x != 0: + swap = ( + result[0].y > result[1].y + or ( + result[0].y == result[1].y + and result[0].x > result[1].x + ) + ) + else: + swap = ( + result[0].x > result[1].x + or ( + result[0].x == result[1].x + and result[0].y > result[1].y + ) + ) + if swap: + var first := result[0] + result[0] = result[1] + result[1] = first + return result + + func _river_source_coordinates( origin: Vector2i, footprint_size: Vector2i, flow_direction: Vector2i, ) -> Array[Vector2i]: + if ( + origin == _river_feature_origin + and footprint_size == _river_feature_footprint_size + and flow_direction == _river_feature_flow_direction + and not _river_feature_source_coordinates.is_empty() + ): + var authored_result: Array[Vector2i] = [] + authored_result.assign(_river_feature_source_coordinates) + return authored_result var northwest := origin var northeast := Vector2i( origin.x + footprint_size.x - 1, @@ -2192,27 +2698,31 @@ func _lake_feature_placement_specs() -> Array[Dictionary]: result.append({"coordinate": southwest, "id": lake_corner_chunk_id, "turns": 1}) result.append({"coordinate": southeast, "id": lake_corner_chunk_id, "turns": 2}) for row: int in range(northwest.y + 1, southwest.y): - result.append({ - "coordinate": Vector2i(northwest.x, row), - "id": lake_edge_chunk_id, - "turns": 0, - }) - result.append({ - "coordinate": Vector2i(northeast.x, row), - "id": lake_edge_chunk_id, - "turns": 2, - }) + _append_lake_perimeter_spec( + result, + Vector2i(northwest.x, row), + lake_edge_chunk_id, + 0, + ) + _append_lake_perimeter_spec( + result, + Vector2i(northeast.x, row), + lake_edge_chunk_id, + 2, + ) for column: int in range(northwest.x + 1, northeast.x): - result.append({ - "coordinate": Vector2i(column, northwest.y), - "id": lake_edge_chunk_id, - "turns": 3, - }) - result.append({ - "coordinate": Vector2i(column, southwest.y), - "id": lake_edge_chunk_id, - "turns": 1, - }) + _append_lake_perimeter_spec( + result, + Vector2i(column, northwest.y), + lake_edge_chunk_id, + 3, + ) + _append_lake_perimeter_spec( + result, + Vector2i(column, southwest.y), + lake_edge_chunk_id, + 1, + ) if _lake_feature_uses_fill: for row: int in range(northwest.y + 1, southwest.y): for column: int in range(northwest.x + 1, northeast.x): @@ -2242,26 +2752,30 @@ func _diagonal_lake_feature_placement_specs( for offset: int in top_side.size(): var top_spec: Dictionary = top_side[offset] var reverse_spec: Dictionary = top_side[top_side.size() - 1 - offset] - result.append({ - "coordinate": Vector2i(northwest.x + 1 + offset, northwest.y), - "id": top_spec["id"], - "turns": top_spec["turns"], - }) - result.append({ - "coordinate": Vector2i(southwest.x + 1 + offset, southwest.y), - "id": reverse_spec["id"], - "turns": posmod(int(reverse_spec["turns"]) + 2, 4), - }) - result.append({ - "coordinate": Vector2i(northwest.x, northwest.y + 1 + offset), - "id": reverse_spec["id"], - "turns": posmod(int(reverse_spec["turns"]) + 1, 4), - }) - result.append({ - "coordinate": Vector2i(northeast.x, northeast.y + 1 + offset), - "id": top_spec["id"], - "turns": posmod(int(top_spec["turns"]) + 3, 4), - }) + _append_lake_perimeter_spec( + result, + Vector2i(northwest.x + 1 + offset, northwest.y), + top_spec["id"] as StringName, + int(top_spec["turns"]), + ) + _append_lake_perimeter_spec( + result, + Vector2i(southwest.x + 1 + offset, southwest.y), + reverse_spec["id"] as StringName, + posmod(int(reverse_spec["turns"]) + 2, 4), + ) + _append_lake_perimeter_spec( + result, + Vector2i(northwest.x, northwest.y + 1 + offset), + reverse_spec["id"] as StringName, + posmod(int(reverse_spec["turns"]) + 1, 4), + ) + _append_lake_perimeter_spec( + result, + Vector2i(northeast.x, northeast.y + 1 + offset), + top_spec["id"] as StringName, + posmod(int(top_spec["turns"]) + 3, 4), + ) if _lake_feature_uses_fill: for row: int in range(northwest.y + 1, southwest.y): for column: int in range(northwest.x + 1, northeast.x): @@ -2273,6 +2787,23 @@ func _diagonal_lake_feature_placement_specs( return result +func _append_lake_perimeter_spec( + result: Array[Dictionary], + coordinate: Vector2i, + stable_id: StringName, + quarter_turns: int, +) -> void: + var selected_id := stable_id + if stable_id == lake_edge_chunk_id and lake_edge_variant_chunk_id != &"": + if posmod(int(generation_seed) + result.size(), 2) == 1: + selected_id = lake_edge_variant_chunk_id + result.append({ + "coordinate": coordinate, + "id": selected_id, + "turns": quarter_turns, + }) + + func _lake_top_side_specs(interior_count: int) -> Array[Dictionary]: var result: Array[Dictionary] = [] if interior_count < 3: @@ -2295,10 +2826,13 @@ func _apply_river_feature() -> bool: return true if ( _river_feature_origin.x < 0 - or mini( - _river_feature_footprint_size.x, - _river_feature_footprint_size.y, - ) != 2 + or _river_feature_placements.is_empty() + or _river_feature_flow_direction == Vector2i.ZERO + or _river_feature_outlet_direction == Vector2i.ZERO + or ( + _river_feature_flow_direction.x * _river_feature_outlet_direction.x + + _river_feature_flow_direction.y * _river_feature_outlet_direction.y + ) != 0 ): push_error("River feature has no reserved terrain region.") return false @@ -2325,149 +2859,7 @@ func _apply_river_feature() -> bool: func _river_feature_placement_specs() -> Array[Dictionary]: var result: Array[Dictionary] = [] - var northwest := _river_feature_origin - var northeast := Vector2i( - _river_feature_origin.x + _river_feature_footprint_size.x - 1, - _river_feature_origin.y, - ) - var southwest := Vector2i( - _river_feature_origin.x, - _river_feature_origin.y + _river_feature_footprint_size.y - 1, - ) - var southeast := ( - _river_feature_origin - + _river_feature_footprint_size - - Vector2i.ONE - ) - match _river_feature_flow_direction: - Vector2i.RIGHT: - result.assign([ - { - "coordinate": northwest, - "id": river_source_right_chunk_id, - "turns": 0, - }, - { - "coordinate": southwest, - "id": river_source_left_chunk_id, - "turns": 0, - }, - { - "coordinate": northeast, - "id": river_outlet_right_chunk_id, - "turns": 0, - }, - { - "coordinate": southeast, - "id": river_outlet_left_chunk_id, - "turns": 0, - }, - ]) - Vector2i.LEFT: - result.assign([ - { - "coordinate": northwest, - "id": river_outlet_left_chunk_id, - "turns": 2, - }, - { - "coordinate": southwest, - "id": river_outlet_right_chunk_id, - "turns": 2, - }, - { - "coordinate": northeast, - "id": river_source_left_chunk_id, - "turns": 2, - }, - { - "coordinate": southeast, - "id": river_source_right_chunk_id, - "turns": 2, - }, - ]) - Vector2i.DOWN: - result.assign([ - { - "coordinate": northwest, - "id": river_source_left_chunk_id, - "turns": 3, - }, - { - "coordinate": northeast, - "id": river_source_right_chunk_id, - "turns": 3, - }, - { - "coordinate": southwest, - "id": river_outlet_left_chunk_id, - "turns": 3, - }, - { - "coordinate": southeast, - "id": river_outlet_right_chunk_id, - "turns": 3, - }, - ]) - Vector2i.UP: - result.assign([ - { - "coordinate": northwest, - "id": river_outlet_right_chunk_id, - "turns": 1, - }, - { - "coordinate": northeast, - "id": river_outlet_left_chunk_id, - "turns": 1, - }, - { - "coordinate": southwest, - "id": river_source_right_chunk_id, - "turns": 1, - }, - { - "coordinate": southeast, - "id": river_source_left_chunk_id, - "turns": 1, - }, - ]) - _: - push_error("River feature has no cardinal flow direction.") - return [] - var river_random := RandomNumberGenerator.new() - river_random.seed = generation_seed ^ 0x4B1D63A7 - var phase := river_random.randi_range(0, 1) - var edge_ids: Array[StringName] = [ - river_edge_chunk_id, - river_edge_variant_chunk_id, - ] - if _river_feature_footprint_size.y == 2: - for offset: int in range(1, _river_feature_footprint_size.x - 1): - var edge_index := posmod(offset - 1 + phase, edge_ids.size()) - result.append({ - "coordinate": Vector2i(northwest.x + offset, northwest.y), - "id": edge_ids[edge_index], - "turns": 0, - }) - result.append({ - "coordinate": Vector2i(southwest.x + offset, southwest.y), - "id": edge_ids[posmod(edge_index + 1, edge_ids.size())], - "turns": 2, - }) - else: - for offset: int in range(1, _river_feature_footprint_size.y - 1): - var edge_index := posmod(offset - 1 + phase, edge_ids.size()) - result.append({ - "coordinate": Vector2i(northwest.x, northwest.y + offset), - "id": edge_ids[edge_index], - "turns": 1, - }) - result.append({ - "coordinate": Vector2i(northeast.x, northeast.y + offset), - "id": edge_ids[posmod(edge_index + 1, edge_ids.size())], - "turns": 3, - }) + result.assign(_river_feature_placements) return result @@ -2984,6 +3376,28 @@ func _calculate_edge_compatibility( second: TerrainChunkVariant, second_edge: TerrainChunkTopology.Edge, ) -> bool: + var first_inlet := _variant_edge_has_connector( + first, + first.definition.water_inlet_edges, + first_edge, + ) + var first_outlet := _variant_edge_has_connector( + first, + first.definition.water_outlet_edges, + first_edge, + ) + var second_inlet := _variant_edge_has_connector( + second, + second.definition.water_inlet_edges, + second_edge, + ) + var second_outlet := _variant_edge_has_connector( + second, + second.definition.water_outlet_edges, + second_edge, + ) + var first_has_water := first_inlet or first_outlet + var second_has_water := second_inlet or second_outlet var profile_tolerance := maxf( edge_match_tolerance, maxf( @@ -3012,30 +3426,26 @@ func _calculate_edge_compatibility( 0.0, profile_tolerance, ) + if ( + not profiles_match + and first_has_water + and second_has_water + and ( + _variant_edge_has_connector( + first, + first.definition.continuous_water_seam_edges, + first_edge, + ) + or _variant_edge_has_connector( + second, + second.definition.continuous_water_seam_edges, + second_edge, + ) + ) + ): + profiles_match = true if not profiles_match: return false - var first_inlet := _variant_edge_has_connector( - first, - first.definition.water_inlet_edges, - first_edge, - ) - var first_outlet := _variant_edge_has_connector( - first, - first.definition.water_outlet_edges, - first_edge, - ) - var second_inlet := _variant_edge_has_connector( - second, - second.definition.water_inlet_edges, - second_edge, - ) - var second_outlet := _variant_edge_has_connector( - second, - second.definition.water_outlet_edges, - second_edge, - ) - var first_has_water := first_inlet or first_outlet - var second_has_water := second_inlet or second_outlet if first_has_water or second_has_water: return ( (first_outlet and second_inlet) diff --git a/world/generation/terrain_chunk_variant.gd b/world/generation/terrain_chunk_variant.gd index f2f9e65..9c2770b 100644 --- a/world/generation/terrain_chunk_variant.gd +++ b/world/generation/terrain_chunk_variant.gd @@ -49,7 +49,7 @@ func topology_signature(quantization: float) -> String: func constraint_signature(quantization: float) -> String: return ( - "%s|neighbors:%s|surfaces:%s|ocean:%d|buried:%d|in:%d|out:%d" + "%s|neighbors:%s|surfaces:%s|ocean:%d|buried:%d|in:%d|out:%d|water_seam:%d" % [ topology_signature(quantization), _neighbor_rule_signature(), @@ -58,6 +58,7 @@ func constraint_signature(quantization: float) -> String: rotated_edge_mask(definition.buried_cliff_seam_edges), rotated_edge_mask(definition.water_inlet_edges), rotated_edge_mask(definition.water_outlet_edges), + rotated_edge_mask(definition.continuous_water_seam_edges), ] )