feat(multiplayer): explain queue and connection health

This commit is contained in:
Josh Creek
2026-09-01 23:11:37 +01:00
parent 9b14109727
commit b15d19eec2
3 changed files with 41 additions and 2 deletions
+25 -2
View File
@@ -186,13 +186,15 @@ func _render(snapshot: Dictionary) -> void:
var waited := _elapsed_seconds
if int(snapshot.get("enqueued_at_unix", 0)) > 0:
waited = float(ControlPlaneClient.state.waited_seconds(int(Time.get_unix_time_from_system())))
detail_label.text = "Waiting %.0fs · revision %d" % [waited, int(snapshot.get("revision", 0))]
detail_label.text = queue_wait_detail_text(int(waited), int(snapshot.get("revision", 0)))
elif phase == MatchmakingState.PROPOSED:
detail_label.text = proposal_countdown_text(int(snapshot.get("expires_at_unix", 0)), int(Time.get_unix_time_from_system()))
elif phase == MatchmakingState.ACCEPTED:
detail_label.text = phase_detail_label(phase)
elif phase in [MatchmakingState.ALLOCATING, MatchmakingState.PROCESS_READY, MatchmakingState.ASSIGNMENT_READY, MatchmakingState.ASSIGNED, MatchmakingState.CONNECTING, MatchmakingState.LIVE]:
elif phase in [MatchmakingState.ALLOCATING, MatchmakingState.PROCESS_READY, MatchmakingState.ASSIGNMENT_READY, MatchmakingState.ASSIGNED]:
detail_label.text = phase_detail_label(phase)
elif phase in [MatchmakingState.CONNECTING, MatchmakingState.LIVE]:
detail_label.text = "%s · %s" % [phase_detail_label(phase), latency_detail_text(NetworkManager.rtt_ms)]
elif phase == MatchmakingState.RESULT_PENDING:
detail_label.text = "The server is confirming the final result"
elif phase == MatchmakingState.COMPLETED:
@@ -238,5 +240,26 @@ static func proposal_countdown_text(expires_at_unix: int, now_unix: int) -> Stri
return "Review proposal · %ds remaining" % maxi(0, expires_at_unix - now_unix)
static func queue_wait_detail_text(waited_seconds: int, revision: int) -> String:
var waited := maxi(0, waited_seconds)
var suffix := "looking for compatible players"
if waited >= 30:
suffix = "widening skill range while keeping latency limits"
elif waited >= 10:
suffix = "matching nearby skill and latency"
return "Waiting %ds · %s · revision %d" % [waited, suffix, maxi(0, revision)]
static func latency_detail_text(rtt_ms: float) -> String:
if not is_finite(rtt_ms) or rtt_ms < 0.0:
return "Latency: measuring"
var rounded := int(round(rtt_ms))
if rtt_ms <= 50.0:
return "Latency: %dms · excellent" % rounded
if rtt_ms <= 100.0:
return "Latency: %dms · good" % rounded
return "Latency: %dms · high" % rounded
static func _can_start_new_search(phase: String) -> bool:
return phase == MatchmakingState.IDLE or phase in [MatchmakingState.CANCELLED, MatchmakingState.EXPIRED, MatchmakingState.FAILED, MatchmakingState.COMPLETED]
+14
View File
@@ -30,3 +30,17 @@ func test_allocation_lifecycle_phases_have_specific_detail_copy() -> void:
assert_true(not Matchmaking.phase_detail_label(phase).is_empty(), "phase %s has lifecycle detail copy" % phase)
assert_true(Matchmaking.phase_detail_label(MatchmakingState.ALLOCATING).contains("dedicated"), "allocation explains dedicated server provisioning")
assert_true(Matchmaking.phase_detail_label(MatchmakingState.CONNECTING).contains("Connecting"), "connecting explains the active transport step")
func test_queue_wait_copy_explains_progress_without_trusting_negative_input() -> void:
assert_eq(Matchmaking.queue_wait_detail_text(-4, -2), "Waiting 0s · looking for compatible players · revision 0", "negative metadata is clamped")
assert_true(Matchmaking.queue_wait_detail_text(10, 3).contains("skill and latency"), "mid-wait explains the compatibility search")
assert_true(Matchmaking.queue_wait_detail_text(30, 4).contains("keeping latency limits"), "long waits explain bounded widening")
func test_latency_copy_fails_closed_and_explains_quality_boundaries() -> void:
assert_eq(Matchmaking.latency_detail_text(-1.0), "Latency: measuring", "missing latency remains honest")
assert_eq(Matchmaking.latency_detail_text(INF), "Latency: measuring", "infinite latency fails closed")
assert_eq(Matchmaking.latency_detail_text(50.0), "Latency: 50ms · excellent", "excellent boundary is inclusive")
assert_eq(Matchmaking.latency_detail_text(100.0), "Latency: 100ms · good", "good boundary is inclusive")
assert_eq(Matchmaking.latency_detail_text(100.1), "Latency: 100ms · high", "high latency is surfaced")