Add selectable startup world layouts

This commit is contained in:
Alexander Sellite 2026-08-20 21:43:04 -04:00
parent 5d55afcc26
commit 3d34ed0bee
24 changed files with 1139 additions and 78 deletions

View file

@ -86,6 +86,7 @@ var _last_server_player_count: int = 0
var _last_server_display_name: String = ""
var _last_server_protocol_version: int = 0
var _last_server_world_seed: int = NetworkProtocol.DEFAULT_WORLD_SEED
var _last_server_world_layout: StringName = WorldLayout.GENERATED
var _server_capabilities: PackedStringArray = PackedStringArray()
var _profile_ready: bool = false
var _player_identity: PlayerIdentityStore
@ -113,6 +114,7 @@ var _session_operator_fingerprints: Dictionary[String, bool] = {}
var _operator_peer_ids: Dictionary[int, bool] = {}
var _local_operator: bool = false
var _host_world_seed: int = NetworkProtocol.DEFAULT_WORLD_SEED
var _host_world_layout: StringName = WorldLayout.GENERATED
func _ready() -> void:
@ -275,6 +277,7 @@ func _register_player_host() -> void:
NetworkProtocol.WORLD_SPAWN_CAPABILITY,
NetworkProtocol.BACKPACK_SHOP_CAPABILITY,
NetworkProtocol.WORLD_GENERATION_CAPABILITY,
NetworkProtocol.WORLD_LAYOUT_CAPABILITY,
]),
)
_registry.update_appearance(1, _local_appearance_snapshot)
@ -531,20 +534,35 @@ func get_last_server_metadata() -> Dictionary:
"player_count": _last_server_player_count,
"max_players": _last_server_max_players,
"world_seed": _last_server_world_seed,
"world_layout": String(_last_server_world_layout),
}
func set_host_world_seed(seed: int) -> bool:
return set_host_world(WorldLayout.GENERATED, seed)
func set_host_world(world_layout: StringName, seed: int) -> bool:
if (
state != State.INACTIVE
or not WorldLayout.is_valid(world_layout)
or seed <= 0
or seed > NetworkProtocol.MAX_WORLD_SEED
):
return false
_host_world_layout = world_layout
_host_world_seed = seed
return true
func get_authoritative_world_layout() -> StringName:
return (
_last_server_world_layout
if is_joined_client()
else _host_world_layout
)
func get_authoritative_world_seed() -> int:
return _last_server_world_seed if is_joined_client() else _host_world_seed
@ -583,6 +601,7 @@ func supports_server_capability(capability: StringName) -> bool:
NetworkProtocol.WORLD_SPAWN_CAPABILITY,
NetworkProtocol.APPEARANCE_PREVIEW_CAPABILITY,
NetworkProtocol.WORLD_GENERATION_CAPABILITY,
NetworkProtocol.WORLD_LAYOUT_CAPABILITY,
"chat_v1",
"mail_v1",
"profile_v1",
@ -1190,6 +1209,15 @@ func submit_client_hello(data: Dictionary) -> void:
NetworkProtocol.RejectionCode.UNSUPPORTED_CLIENT,
)
return
if (
_host_world_layout == WorldLayout.STARTER_ISLAND
and NetworkProtocol.WORLD_LAYOUT_CAPABILITY not in client_capabilities
):
_reject_peer(
sender_id,
NetworkProtocol.RejectionCode.UNSUPPORTED_CLIENT,
)
return
var identity: Dictionary = _authenticated_identity_cache.get(sender_id, {})
if identity.is_empty():
_reject_peer(sender_id, NetworkProtocol.RejectionCode.INVALID_IDENTITY_PROOF)
@ -1278,6 +1306,7 @@ func submit_client_hello(data: Dictionary) -> void:
session_max_players,
_session_display_name,
_host_world_seed,
_host_world_layout,
)
)
receive_spawn_list.rpc_id(sender_id, _build_spawn_list())
@ -1332,6 +1361,9 @@ func receive_server_hello(data: Dictionary) -> void:
or typeof(data.get("game_version")) != TYPE_STRING
or typeof(data.get("rejection_code")) != TYPE_INT
or typeof(data.get("world_seed")) != TYPE_INT
or typeof(
data.get("world_layout", String(WorldLayout.GENERATED))
) not in [TYPE_STRING, TYPE_STRING_NAME]
):
_teardown_peer()
_fail("The server sent an invalid handshake response.")
@ -1362,6 +1394,14 @@ func receive_server_hello(data: Dictionary) -> void:
_teardown_peer()
_fail("The server sent an invalid world seed.")
return
var received_world_layout := WorldLayout.normalized(
data.get("world_layout", String(WorldLayout.GENERATED)),
&"",
)
if received_world_layout.is_empty():
_teardown_peer()
_fail("The server sent an invalid world layout.")
return
_session_id = str(data.get("session_id", ""))
_last_server_max_players = int(data.get(
"max_players",
@ -1373,6 +1413,7 @@ func receive_server_hello(data: Dictionary) -> void:
"protocol_version", NetworkProtocol.PROTOCOL_VERSION
))
_last_server_world_seed = received_world_seed
_last_server_world_layout = received_world_layout
_server_capabilities = PackedStringArray()
var advertised_capabilities: Variant = data.get(
"capability_flags", PackedStringArray()
@ -1391,6 +1432,13 @@ func receive_server_hello(data: Dictionary) -> void:
_teardown_peer()
_fail("This server does not support generated worlds.")
return
if (
received_world_layout == WorldLayout.STARTER_ISLAND
and NetworkProtocol.WORLD_LAYOUT_CAPABILITY not in _server_capabilities
):
_teardown_peer()
_fail("This server does not support selectable world layouts.")
return
var local_peer_id: int = multiplayer.get_unique_id()
_registry.clear()
_registry.add_peer(
@ -1407,6 +1455,7 @@ func receive_server_hello(data: Dictionary) -> void:
NetworkProtocol.WORLD_WEATHER_CAPABILITY,
NetworkProtocol.BACKPACK_SHOP_CAPABILITY,
NetworkProtocol.WORLD_GENERATION_CAPABILITY,
NetworkProtocol.WORLD_LAYOUT_CAPABILITY,
]),
)
_registry.update_appearance(local_peer_id, _local_appearance_snapshot)