fix(multiplayer): enforce drain at admission

This commit is contained in:
Josh Creek
2026-09-02 19:04:56 +01:00
parent 670466dbd7
commit 0bca441ca1
3 changed files with 34 additions and 4 deletions
+14 -4
View File
@@ -169,9 +169,10 @@ static func reservation_identity_matches(slot_identity: String, incoming_identit
func _on_peer_disconnected(peer_id: int) -> void:
if not multiplayer.is_server():
return
if not admissions_open:
await _reject(multiplayer.get_remote_sender_id(), "server is draining")
return
_cleanup_disconnected_peer(peer_id)
func _cleanup_disconnected_peer(peer_id: int) -> void:
NetworkManager.invalidate_peer(peer_id)
_remove_player(peer_id)
@@ -210,7 +211,8 @@ func _remove_player(peer_id: int) -> void:
# from inside signal-handling: by then poll() has fully returned, every
# disconnect event in this batch has been dispatched, and get_peers()
# reflects the settled, genuinely-still-connected set.
call_deferred("_broadcast_player_left", peer_id)
if is_inside_tree():
call_deferred("_broadcast_player_left", peer_id)
func _broadcast_player_left(peer_id: int) -> void:
@@ -239,6 +241,10 @@ static func _sanitize_shutdown_reason(raw: String) -> String:
return clean if not clean.is_empty() else "server_shutdown"
static func admission_rejection(is_open: bool) -> String:
return "" if is_open else "server is draining"
# Balances a new joiner onto whichever team currently has fewer players
# (ties go to team 0). Server only.
func _pick_balanced_team() -> int:
@@ -261,6 +267,10 @@ func _hello(protocol_version: int, tick_hz: int, player_name: String, supplied_j
var peer_id := multiplayer.get_remote_sender_id()
if roster.has(peer_id):
return # duplicate hello from an already-accepted peer; ignore
var admission_error := admission_rejection(admissions_open)
if not admission_error.is_empty():
await _reject(peer_id, admission_error)
return
if protocol_version != NetCodec.PROTOCOL_VERSION:
await _reject(peer_id, "protocol version mismatch: server=%d client=%d" % [NetCodec.PROTOCOL_VERSION, protocol_version])