From ba34796f53d876b0edffe328893270ab26dbc053 Mon Sep 17 00:00:00 2001 From: Askaholic Date: Sat, 20 Jun 2020 00:18:11 -0800 Subject: [PATCH] Restart search automatically after a timeout --- server/ladder_service.py | 25 +++++++++++- tests/integration_tests/test_matchmaker.py | 45 ++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/server/ladder_service.py b/server/ladder_service.py index d3a67b60f..ec333a0a4 100644 --- a/server/ladder_service.py +++ b/server/ladder_service.py @@ -379,9 +379,10 @@ async def confirm_match( await self.start_game(s1.players, s2.players, queue) except OfferTimeoutError: + unready_players = list(offer.get_unready_players()) self._logger.info( "Match failed to start. Some players did not ready up in time: %s", - list(player.login for player in offer.get_unready_players()) + [player.login for player in unready_players] ) # TODO: Refactor duplication msg = {"command": "match_cancelled"} @@ -389,7 +390,27 @@ async def confirm_match( if player.state == PlayerState.STARTING_AUTOMATCH: player.state = PlayerState.IDLE player.write_message(msg) - # TODO: Unmatch and return to queue + + # Return any player that accepted the match back to the queue + # TODO: make this work with parties + for player in s1.players: + if player in unready_players: + self.cancel_search(player) + else: + s1.unmatch() + asyncio.create_task(queue.search(s1)) + + for player in s2.players: + if player in unready_players: + self.cancel_search(player) + else: + s2.unmatch() + asyncio.create_task(queue.search(s2)) + except Exception as e: + self._logger.exception( + "Error processing match between searches %s, and %s: %s", + s1, s2, e + ) def create_match_offer(self, players: Iterable[Player]): offer = MatchOffer( diff --git a/tests/integration_tests/test_matchmaker.py b/tests/integration_tests/test_matchmaker.py index ffddc2edc..3fc684fe9 100644 --- a/tests/integration_tests/test_matchmaker.py +++ b/tests/integration_tests/test_matchmaker.py @@ -122,6 +122,51 @@ async def test_game_matchmaking_start_while_matched(lobby_server): assert msg["text"].startswith("Can't join a queue while ladder1 is in") +@fast_forward(100) +async def test_game_matchmaking_search_after_timeout(lobby_server, database): + proto1 = await queue_player_for_matchmaking( + ('ladder1', 'ladder1'), + lobby_server, + "ladder1v1" + ) + proto2 = await queue_player_for_matchmaking( + ('ladder2', 'ladder2'), + lobby_server, + "ladder1v1" + ) + + await read_until_command(proto1, "match_info") + await read_until_command(proto2, "match_info") + + # Only player 1 readies up + await proto1.send_message({"command": "match_ready"}) + + # So the match times out + await read_until_command(proto1, "match_cancelled") + await read_until_command(proto2, "match_cancelled") + + # At this point the search for player 2 should be cancelled, but player 1 + # should still be in the queue + msg = await read_until_command(proto2, "search_info") + assert msg == { + "command": "search_info", + "queue_name": "ladder1v1", + "state": "stop" + } + + # Player 2 joins the queue again + await proto2.send_message({ + "command": "game_matchmaking", + "state": "start", + "faction": "seraphim", + "mod": "ladder1v1" + }) + + # The players should match + await read_until_command(proto1, "match_info") + await read_until_command(proto2, "match_info") + + @fast_forward(120) async def test_game_matchmaking_timeout(lobby_server, game_service): proto1, proto2 = await queue_players_for_matchmaking(lobby_server)