mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
fix multiplayer snapshot disconnect race
This commit is contained in:
@@ -264,6 +264,11 @@ func send_input(bytes: PackedByteArray) -> void:
|
||||
|
||||
|
||||
func send_snapshot(peer_id: int, bytes: PackedByteArray) -> void:
|
||||
# A server-side disconnect can leave peer_id in get_peers() until the
|
||||
# current poll batch settles. Do not enter Godot's RPC path for that stale
|
||||
# target; NetSim repeats this check at fire time for delayed sends.
|
||||
if not NetworkManager.can_send_to_peer(peer_id):
|
||||
return
|
||||
_track_sent(bytes.size())
|
||||
NetSim.send(func() -> void: _snapshot.rpc_id(peer_id, bytes), peer_id)
|
||||
|
||||
@@ -477,6 +482,7 @@ func _disconnect_abusive_peer(peer_id: int, reason: String) -> void:
|
||||
# which does not carry the peer, the reason or a timestamp into the log
|
||||
# stream a container actually captures.
|
||||
ServerLog.warn("peer_kicked", {"peer_id": peer_id, "reason": reason})
|
||||
NetworkManager.invalidate_peer(peer_id)
|
||||
_peer_input_state.erase(peer_id)
|
||||
if multiplayer.multiplayer_peer is ENetMultiplayerPeer:
|
||||
multiplayer.multiplayer_peer.disconnect_peer(peer_id)
|
||||
|
||||
@@ -71,6 +71,7 @@ var is_server := false
|
||||
var is_client := false
|
||||
var _peer: MultiplayerPeer # keep a strong ref alongside multiplayer.multiplayer_peer
|
||||
var active_transport := ""
|
||||
var _invalidated_peer_ids: Dictionary = {}
|
||||
|
||||
var rtt_ms := -1.0 # min-RTT sample currently in the window; -1 = no sample yet
|
||||
var clock_offset_ms := 0.0 # add to a local Time.get_ticks_msec() reading to estimate the server's clock
|
||||
@@ -127,6 +128,27 @@ func poll() -> void:
|
||||
multiplayer.poll()
|
||||
|
||||
|
||||
# A peer can be removed from the transport while Godot is still draining the
|
||||
# same poll batch. During that interval get_peers() may still contain it, but
|
||||
# an RPC send already fails because ENet has torn down its channels.
|
||||
func invalidate_peer(peer_id: int) -> void:
|
||||
_invalidated_peer_ids[peer_id] = true
|
||||
|
||||
|
||||
func can_send_to_peer(peer_id: int) -> bool:
|
||||
if _invalidated_peer_ids.has(peer_id):
|
||||
return false
|
||||
if _peer == null or _peer is OfflineMultiplayerPeer:
|
||||
return false
|
||||
# A listening server's peer status is transport/version-specific; the
|
||||
# authoritative server is valid as soon as it owns a peer and the target
|
||||
# appears in get_peers(). Clients, however, must not dispatch while their
|
||||
# connection is still handshaking.
|
||||
if not is_server and _peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTED:
|
||||
return false
|
||||
return peer_id in multiplayer.get_peers()
|
||||
|
||||
|
||||
func available_transports() -> PackedStringArray:
|
||||
var transports := PackedStringArray([TRANSPORT_ENET])
|
||||
if SteamTransportScript.new().is_available():
|
||||
@@ -185,6 +207,7 @@ func shutdown() -> void:
|
||||
peer.close()
|
||||
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
|
||||
_peer = null
|
||||
_invalidated_peer_ids.clear()
|
||||
active_transport = ""
|
||||
is_server = false
|
||||
is_client = false
|
||||
|
||||
Reference in New Issue
Block a user