mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-13 23:22:08 +00:00
fix(multiplayer): surface matchmaking connect failures to the player
Closes §8.43's 'failed-reconnect UX' gap, found immediately after wiring connect_to_assignment() itself: even with that fix in place, a connection failure had nowhere to go. connect_to_assignment()'s synchronous failures (assignment missing/expired, invalid endpoint, NetworkManager.join() erroring immediately) only ever emitted assignment_connection_failed -- a signal nothing in the client listened to. state.phase would stay stuck at ASSIGNED, the UI would keep showing "Your match server is ready" forever, with no way back to a fresh search. Worse, the likelier real-world failure mode had no handler at all: NetworkManager.join() returns OK immediately once the attempt starts, but the actual ENet handshake can still fail asynchronously afterward (unreachable server, refused connection, ENet's own ~5s connect timeout). This is exactly the gap main_menu.gd's own _on_connection_failed exists to cover for the direct-join flow (see its header comment) -- nothing covered the equivalent for a matchmaking-driven connect. ControlPlaneClient now connects both assignment_connection_failed and NetworkManager.connection_failed (guarded to state.phase == CONNECTING, so it never misattributes an unrelated direct-join failure to a matchmaking search) to state.fail(...), so either failure mode now surfaces as a failed search the player can actually retry from. Verified: three new test_control_plane_client.gd tests cover the synchronous failure path, the async NetworkManager.connection_failed path (via a real end-to-end ASSIGNED -> CONNECTING flow), and that an unrelated connection_failed outside CONNECTING is correctly ignored. 220/220 tests pass, stable across 3 repeated runs, no crash, no engine-level error; full make verify-multiplayer-local and the complete make verify-enet-integration suite (all five cases) both clean; zero new crash reports throughout. Also fixes a markdown table-integrity mistake introduced while documenting this in the same edit pass: an earlier Edit call accidentally duplicated a sentence and dropped the row's closing 'remains' clause in §8.43 -- caught and corrected before commit via the usual pipe-count check.
This commit is contained in:
@@ -62,6 +62,32 @@ func _ready() -> void:
|
||||
_request.request_completed.connect(_on_request_completed)
|
||||
state.resync_required.connect(_on_resync_required)
|
||||
_websocket = WebSocketPeer.new()
|
||||
assignment_connection_failed.connect(_on_assignment_connection_failed)
|
||||
NetworkManager.connection_failed.connect(_on_network_connection_failed)
|
||||
|
||||
|
||||
# Covers §8.43's "failed reconnect UX": connect_to_assignment()'s own
|
||||
# synchronous failures (assignment missing/expired, invalid endpoint,
|
||||
# NetworkManager.join() erroring immediately) previously only emitted
|
||||
# assignment_connection_failed -- a signal nothing in the client actually
|
||||
# listened to. state.phase would stay stuck at ASSIGNED, the UI would keep
|
||||
# showing "Your match server is ready" forever, and there was no way back to
|
||||
# a fresh search.
|
||||
func _on_assignment_connection_failed(detail: String) -> void:
|
||||
state.fail(detail)
|
||||
|
||||
|
||||
# The likelier real-world failure than the synchronous one above:
|
||||
# NetworkManager.join() returns OK immediately (the attempt started), but the
|
||||
# actual ENet handshake fails asynchronously later -- unreachable server,
|
||||
# refused connection, ENet's own ~5s connect timeout. This is exactly the gap
|
||||
# main_menu.gd's own _on_connection_failed exists to cover for the direct-join
|
||||
# flow (see its header comment); nothing covered it for a matchmaking-driven
|
||||
# connect. Guarded to CONNECTING so this never reacts to an unrelated
|
||||
# connection_failed, such as one belonging to main_menu.gd's own direct join.
|
||||
func _on_network_connection_failed() -> void:
|
||||
if state.phase == MatchmakingState.CONNECTING:
|
||||
state.fail("Unable to connect to the match server")
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
|
||||
Reference in New Issue
Block a user