diff --git a/server/tests/test_player_state_integration.py b/server/tests/test_player_state_integration.py index fd9ac09..f487869 100644 --- a/server/tests/test_player_state_integration.py +++ b/server/tests/test_player_state_integration.py @@ -103,11 +103,28 @@ def wait_for_stat(server: FalloutTogetherServer, key: str, minimum: int, timeout raise AssertionError(f"stat {key} did not reach {minimum}") +def establish_transforms( + server: FalloutTogetherServer, + sender: socket.socket, + receiver: socket.socket, + *, + same_interest: bool, +) -> None: + send_packet(sender, transform()) + receiver_transform = transform( + cellId="00000001" if same_interest else "00000002", + worldspaceId="0000003C" if same_interest else "00000099", + ) + send_packet(receiver, receiver_transform) + wait_for_stat(server, "transformPacketsReceived", 2) + + def test_player_state_relay_uses_server_owned_identity(): server = start_server() sender, sender_welcome = connect_v2(server) receiver, _ = connect_v2(server) try: + establish_transforms(server, sender, receiver, same_interest=True) send_packet(sender, player_state()) relayed = recv_until(receiver, "playerState") assert relayed["playerId"] == sender_welcome["playerId"] @@ -148,18 +165,61 @@ def test_v2_transform_strips_reliable_player_state_fields(): server.stop() -def test_new_v2_client_receives_cached_player_state_before_any_transform(): +def test_out_of_interest_player_state_strips_action_events_but_keeps_durable_state(): + server = start_server() + sender, _ = connect_v2(server) + receiver, _ = connect_v2(server) + try: + establish_transforms(server, sender, receiver, same_interest=False) + send_packet(sender, player_state()) + relayed = recv_until(receiver, "playerState") + assert relayed["characterName"] == "Sole Survivor" + assert relayed["equippedItems"] == [{"slot": "rightHand", "formId": "000000FF"}] + assert "actionEvents" not in relayed + finally: + sender.close() + receiver.close() + server.stop() + + +def test_out_of_interest_action_only_player_state_is_not_relayed(): + server = start_server() + sender, _ = connect_v2(server) + receiver, _ = connect_v2(server) + try: + establish_transforms(server, sender, receiver, same_interest=False) + send_packet( + sender, + { + "type": "playerState", + "actionEvents": [{"sequence": 4, "type": 3, "eventName": "fireSingle"}], + }, + ) + wait_for_stat(server, "playerStatePacketsReceived", 1) + with pytest.raises(AssertionError): + recv_until(receiver, "playerState", timeout=0.2) + finally: + sender.close() + receiver.close() + server.stop() + + +def test_new_v2_client_receives_cached_player_state_without_stale_action_events(): server = start_server() sender, sender_welcome = connect_v2(server) receiver = None try: - send_packet(sender, player_state(actionEvents=[])) + send_packet(sender, transform()) + wait_for_stat(server, "transformPacketsReceived", 1) + send_packet(sender, player_state()) wait_for_stat(server, "playerStatePacketsReceived", 1) receiver, _ = connect_v2(server) cached = recv_until(receiver, "playerState") assert cached["playerId"] == sender_welcome["playerId"] assert cached["characterName"] == "Sole Survivor" + assert cached["equippedItems"] == [{"slot": "rightHand", "formId": "000000FF"}] + assert "actionEvents" not in cached finally: sender.close() if receiver is not None: