feat: expand progression and multiplayer systems
Add named save slots, progression import/export, and a unified play flow. Add live friend requests, presence, invitations, and relationship controls without durable discovery-server social storage. Advance the network protocol with isolated channels, movement reconciliation, late-join recovery, fishing replication, and animation synchronization. Preserve per-species catch totals, refine generated-world startup and water recovery, and complete the related input and interface improvements.
This commit is contained in:
parent
1db1a5b754
commit
3b84bfe3a0
97 changed files with 7869 additions and 982 deletions
|
|
@ -79,8 +79,6 @@ func _ready() -> void:
|
|||
_validate_biome_catalog()
|
||||
_configure_static_water()
|
||||
_build_shoreline_reference()
|
||||
if not generate_world(initial_seed):
|
||||
push_error("The initial generated world could not be built.")
|
||||
|
||||
|
||||
func generate_world(seed: int) -> bool:
|
||||
|
|
@ -100,6 +98,10 @@ func get_generation_seed() -> int:
|
|||
return _current_seed
|
||||
|
||||
|
||||
func is_world_generated() -> bool:
|
||||
return is_instance_valid(_generator.get_generated_chunks_root())
|
||||
|
||||
|
||||
func get_playable_half_extents() -> Vector2:
|
||||
var size := Vector2(
|
||||
float(_generator.grid_size.x),
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const MAX_PACKED_SOLVER_VARIANTS := 62
|
|||
@export var generation_seed := 13001
|
||||
@export var generate_on_ready := true
|
||||
@export var build_collision := true
|
||||
@export_range(1, 16, 1) var collision_batch_size := 4
|
||||
@export var show_chunk_labels := false
|
||||
@export var force_center_chunk_id: StringName = &"chunk_0000"
|
||||
@export var required_chunk_ids := PackedStringArray()
|
||||
|
|
@ -3928,9 +3929,102 @@ func _build_solution_root() -> Node3D:
|
|||
if not _add_stacked_elevated_chunks(solution_root):
|
||||
solution_root.free()
|
||||
return null
|
||||
if build_collision and collision_batch_size > 1:
|
||||
_batch_generated_terrain_collision(solution_root)
|
||||
return solution_root
|
||||
|
||||
|
||||
func _batch_generated_terrain_collision(solution_root: Node3D) -> void:
|
||||
var shapes_by_batch: Dictionary[Vector2i, Array] = {}
|
||||
var host_by_batch: Dictionary[Vector2i, Node3D] = {}
|
||||
var bodies_to_remove: Array[StaticBody3D] = []
|
||||
for chunk_node: Node in solution_root.get_children():
|
||||
var chunk_root := chunk_node as Node3D
|
||||
if chunk_root == null:
|
||||
continue
|
||||
var coordinate: Vector2i = chunk_root.get_meta(
|
||||
&"terrain_chunk_coordinate",
|
||||
Vector2i.ZERO,
|
||||
)
|
||||
var batch_coordinate := Vector2i(
|
||||
floori(float(coordinate.x) / float(collision_batch_size)),
|
||||
floori(float(coordinate.y) / float(collision_batch_size)),
|
||||
)
|
||||
if not host_by_batch.has(batch_coordinate):
|
||||
host_by_batch[batch_coordinate] = chunk_root
|
||||
var batch_shapes: Array = shapes_by_batch.get(
|
||||
batch_coordinate,
|
||||
[],
|
||||
)
|
||||
for value: Node in chunk_root.find_children(
|
||||
"TerrainShape",
|
||||
"CollisionShape3D",
|
||||
true,
|
||||
false,
|
||||
):
|
||||
var collision_shape := value as CollisionShape3D
|
||||
if collision_shape == null:
|
||||
continue
|
||||
var collision_body := collision_shape.get_parent() as StaticBody3D
|
||||
if collision_shape.shape == null or collision_body == null:
|
||||
continue
|
||||
var shape_to_solution := _transform_to_ancestor(
|
||||
collision_shape,
|
||||
solution_root,
|
||||
)
|
||||
batch_shapes.append({
|
||||
"shape": collision_shape.shape,
|
||||
"transform": shape_to_solution,
|
||||
})
|
||||
if collision_body not in bodies_to_remove:
|
||||
bodies_to_remove.append(collision_body)
|
||||
shapes_by_batch[batch_coordinate] = batch_shapes
|
||||
while not bodies_to_remove.is_empty():
|
||||
var collision_body: StaticBody3D = bodies_to_remove.pop_back()
|
||||
collision_body.free()
|
||||
for batch_coordinate: Vector2i in shapes_by_batch:
|
||||
var batch_shapes: Array = shapes_by_batch[batch_coordinate]
|
||||
if batch_shapes.is_empty():
|
||||
continue
|
||||
var host_root: Node3D = host_by_batch.get(batch_coordinate)
|
||||
if host_root == null:
|
||||
continue
|
||||
var body := StaticBody3D.new()
|
||||
body.name = "TerrainCollisionBatch_%d_%d" % [
|
||||
batch_coordinate.x,
|
||||
batch_coordinate.y,
|
||||
]
|
||||
body.collision_layer = 1
|
||||
body.collision_mask = 0
|
||||
body.set_meta(&"terrain_collision_batch", batch_coordinate)
|
||||
host_root.add_child(body)
|
||||
var solution_to_body: Transform3D = host_root.transform.affine_inverse()
|
||||
for shape_index: int in batch_shapes.size():
|
||||
var record: Dictionary = batch_shapes[shape_index]
|
||||
var collision := CollisionShape3D.new()
|
||||
collision.name = "TerrainShape_%d" % shape_index
|
||||
collision.shape = record.get("shape") as Shape3D
|
||||
collision.transform = (
|
||||
solution_to_body
|
||||
* (record.get("transform", Transform3D.IDENTITY) as Transform3D)
|
||||
)
|
||||
body.add_child(collision)
|
||||
|
||||
|
||||
static func _transform_to_ancestor(
|
||||
node: Node3D,
|
||||
ancestor: Node3D,
|
||||
) -> Transform3D:
|
||||
var result := Transform3D.IDENTITY
|
||||
var current: Node3D = node
|
||||
while current != ancestor:
|
||||
result = current.transform * result
|
||||
current = current.get_parent() as Node3D
|
||||
if current == null:
|
||||
return Transform3D.IDENTITY
|
||||
return result
|
||||
|
||||
|
||||
func _add_stacked_elevated_chunks(solution_root: Node3D) -> bool:
|
||||
for index: int in _stacked_elevated_placements.size():
|
||||
var record := _stacked_elevated_placements[index]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue