Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions server/gameconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ async def _handle_idle_state(self):
"""
assert self.game

if self.state is not GameConnectionState.INITIALIZING:
self._logger.warning(
"Ignoring unexpected 'Idle' state when state was %s",
self.state,
)
return

if self.player == self.game.host:
self.game.state = GameState.LOBBY
self._state = GameConnectionState.CONNECTED_TO_HOST
Expand All @@ -132,6 +139,13 @@ async def _handle_lobby_state(self):
"""
player_state = self.player.state
if player_state == PlayerState.HOSTING:
if self.game.hosted_at is not None:
self._logger.warning(
"Ignoring unexpected 'Lobby' state sent when the game was "
"already hosted.",
)
return

await self.send_HostGame(self.game.map.folder_name)
self.game.set_hosted()
# If the player is joining, we connect him to host
Expand Down
42 changes: 42 additions & 0 deletions tests/integration_tests/test_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,48 @@ async def test_ladder_game_not_joinable(lobby_server):
}


@fast_forward(60)
async def test_gamestate_lobby_double_game_instance(lobby_server):
"""There was a bug in the client that was causing multiple game instances
to launch simultaneously. This could cause the GpgNet messages in the game
startup sequence to be sent twice.
"""
_, _, host_proto = await connect_and_sign_in(
("test", "test_password"), lobby_server
)
_, _, guest_proto = await connect_and_sign_in(
("Rhiza", "puff_the_magic_dragon"), lobby_server
)
await read_until_command(host_proto, "game_info")
await read_until_command(guest_proto, "game_info")

await host_proto.send_message({
"command": "game_host",
"mod": "faf",
"visibility": "public",
})
msg = await read_until_command(host_proto, "game_launch")
game_id = int(msg["uid"])

for _ in range(2):
await host_proto.send_message({
"target": "game",
"command": "GameState",
"args": ["Idle"]
})

for _ in range(2):
await host_proto.send_message({
"target": "game",
"command": "GameState",
"args": ["Lobby"]
})

await read_until_command(host_proto, "HostGame", target="game")

await join_game(guest_proto, game_id)


@pytest.mark.flaky
@fast_forward(60)
async def test_gamestate_ended_clears_references(
Expand Down
21 changes: 18 additions & 3 deletions tests/unit_tests/test_gameconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,33 @@ async def test_connect_to_peer_disconnected(game_connection):
await game_connection.connect_to_peer(peer)


async def test_handle_action_GameState_idle_adds_connection(
async def test_handle_action_GameState_idle_hosting(
game: Game,
game_connection: GameConnection,
players
):
players.joining.game = game
game_connection.player = players.hosting
game_connection.game = game

await game_connection.handle_action("GameState", ["Idle"])

game.add_game_connection.assert_called_with(game_connection)
game.add_game_connection.assert_called_once_with(game_connection)


async def test_handle_action_GameState_idle_joining(
game: Game,
game_connection: GameConnection,
players
):
game_connection.player = players.joining
game_connection.game = game

await game_connection.handle_action("GameState", ["Idle"])

assert players.joining.state == PlayerState.JOINING
assert game_connection.state == GameConnectionState.INITIALIZED

game.add_game_connection.assert_not_called()


async def test_handle_action_GameState_idle_sets_player_state(
Expand Down