diff --git a/client/tests/test_sprint2_proof.gd b/client/tests/test_sprint2_proof.gd index 19dc96834..a3bc57302 100644 --- a/client/tests/test_sprint2_proof.gd +++ b/client/tests/test_sprint2_proof.gd @@ -16,6 +16,12 @@ extends GdUnitTestSuite const CONNECT_TIMEOUT: float = 3.0 const RESPONSE_TIMEOUT: float = 5.0 +# Server move cooldown: the Gauntlet player is Walk stance (ticks_per_move = 2, +# server stance.rs). A move input arriving within that window is silently +# throttled away (movement.rs::apply_move -> PlayerMoveCooldown::try_move). +# Space consecutive sends past it (2 ticks + 1 margin for apply/snapshot lag) +# so back-to-back moves can never race the cooldown. +const COOLDOWN_TICKS: int = 3 const MAX_PORT_ATTEMPTS: int = 5 var _server_pid: int = -1 @@ -128,6 +134,27 @@ func _send_and_receive( assert_that(actual.is_equal_approx(expect_position)).override_failure_message( "player must reach %s after '%s' — last seen %s" % [expect_position, action_name, actual] ).is_true() + # Space the next move past the per-stance cooldown. The server silently + # drops a move that arrives within ticks_per_move ticks of the previous + # one; without this wait, back-to-back sends race the cooldown and an + # occasional move is throttled, leaving the player one tile short (flaky). + # Wait for the server clock to advance COOLDOWN_TICKS past the landing + # tick so the next send can never be throttled. The player is stationary + # meanwhile, so the fresher snapshot is still valid for the caller. + var landed_tick: int = int(snapshot.tick) + var spacing_elapsed := 0.0 + while spacing_elapsed < RESPONSE_TIMEOUT: + _bridge.poll() + var m := _bridge.poll_message() + if m.size() > 0: + var d: Variant = Protocol.decode_snapshot(m) + if d != null: + snapshot = d + if int(d.tick) >= landed_tick + COOLDOWN_TICKS: + break + continue + await get_tree().create_timer(0.05).timeout + spacing_elapsed += 0.05 return snapshot