Add broadcast_to_spectators helper
Helper function sends messages to all players at the same x,y coordinates as the source player, skipping the source player themselves. Used for IF spectator broadcasting.
This commit is contained in:
parent
c3f8c8cf12
commit
3dd095b9ea
3 changed files with 41 additions and 30 deletions
|
|
@ -33,9 +33,7 @@ def _list_stories() -> list[str]:
|
||||||
if not _stories_dir.exists():
|
if not _stories_dir.exists():
|
||||||
return []
|
return []
|
||||||
return sorted(
|
return sorted(
|
||||||
p.stem
|
p.stem for p in _stories_dir.iterdir() if p.suffix in _STORY_EXTENSIONS
|
||||||
for p in _stories_dir.iterdir()
|
|
||||||
if p.suffix in _STORY_EXTENSIONS
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from mudlib.player import Player
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -103,3 +107,12 @@ class IFSession:
|
||||||
|
|
||||||
result = "".join(output)
|
result = "".join(output)
|
||||||
return result.rstrip()
|
return result.rstrip()
|
||||||
|
|
||||||
|
|
||||||
|
async def broadcast_to_spectators(player: "Player", message: str) -> None:
|
||||||
|
"""Send message to all other players at the same location."""
|
||||||
|
from mudlib.player import players
|
||||||
|
|
||||||
|
for other in players.values():
|
||||||
|
if other.name != player.name and other.x == player.x and other.y == player.y:
|
||||||
|
await other.send(message)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from unittest.mock import AsyncMock, MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mudlib.if_session import IFResponse, IFSession
|
from mudlib.if_session import IFResponse
|
||||||
from mudlib.player import Player, players
|
from mudlib.player import Player, players
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -30,27 +30,33 @@ def clear_players():
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def player_a(mock_reader, mock_writer):
|
def player_a():
|
||||||
"""Player A at (5, 5) who will be playing IF."""
|
"""Player A at (5, 5) who will be playing IF."""
|
||||||
return Player(
|
writer = MagicMock()
|
||||||
name="PlayerA", x=5, y=5, reader=mock_reader, writer=mock_writer
|
writer.write = MagicMock()
|
||||||
)
|
writer.drain = AsyncMock()
|
||||||
|
reader = MagicMock()
|
||||||
|
return Player(name="PlayerA", x=5, y=5, reader=reader, writer=writer)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def player_b(mock_reader, mock_writer):
|
def player_b():
|
||||||
"""Player B at (5, 5) who will be spectating."""
|
"""Player B at (5, 5) who will be spectating."""
|
||||||
return Player(
|
writer = MagicMock()
|
||||||
name="PlayerB", x=5, y=5, reader=mock_reader, writer=mock_writer
|
writer.write = MagicMock()
|
||||||
)
|
writer.drain = AsyncMock()
|
||||||
|
reader = MagicMock()
|
||||||
|
return Player(name="PlayerB", x=5, y=5, reader=reader, writer=writer)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def player_c(mock_reader, mock_writer):
|
def player_c():
|
||||||
"""Player C at different coords (10, 10)."""
|
"""Player C at different coords (10, 10)."""
|
||||||
return Player(
|
writer = MagicMock()
|
||||||
name="PlayerC", x=10, y=10, reader=mock_reader, writer=mock_writer
|
writer.write = MagicMock()
|
||||||
)
|
writer.drain = AsyncMock()
|
||||||
|
reader = MagicMock()
|
||||||
|
return Player(name="PlayerC", x=10, y=10, reader=reader, writer=writer)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|
@ -79,11 +85,7 @@ async def test_spectator_sees_if_output(player_a, player_b):
|
||||||
await player_a.send(response.output)
|
await player_a.send(response.output)
|
||||||
|
|
||||||
# Broadcast to spectators
|
# Broadcast to spectators
|
||||||
spectator_msg = (
|
spectator_msg = f"[{player_a.name}'s terminal]\r\n> {command}\r\n{response.output}"
|
||||||
f"[{player_a.name}'s terminal]\r\n"
|
|
||||||
f"> {command}\r\n"
|
|
||||||
f"{response.output}"
|
|
||||||
)
|
|
||||||
await broadcast_to_spectators(player_a, spectator_msg)
|
await broadcast_to_spectators(player_a, spectator_msg)
|
||||||
|
|
||||||
# Player B should have received the message
|
# Player B should have received the message
|
||||||
|
|
@ -118,11 +120,7 @@ async def test_spectator_not_on_same_tile_sees_nothing(player_a, player_c):
|
||||||
await player_a.send(response.output)
|
await player_a.send(response.output)
|
||||||
|
|
||||||
# Broadcast to spectators
|
# Broadcast to spectators
|
||||||
spectator_msg = (
|
spectator_msg = f"[{player_a.name}'s terminal]\r\n> {command}\r\n{response.output}"
|
||||||
f"[{player_a.name}'s terminal]\r\n"
|
|
||||||
f"> {command}\r\n"
|
|
||||||
f"{response.output}"
|
|
||||||
)
|
|
||||||
await broadcast_to_spectators(player_a, spectator_msg)
|
await broadcast_to_spectators(player_a, spectator_msg)
|
||||||
|
|
||||||
# Player C should NOT have received anything
|
# Player C should NOT have received anything
|
||||||
|
|
@ -171,12 +169,14 @@ async def test_broadcast_to_spectators_skips_self(player_a, player_b):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_multiple_spectators(player_a, player_b, mock_reader, mock_writer):
|
async def test_multiple_spectators(player_a, player_b):
|
||||||
"""Multiple spectators at same location all see IF output."""
|
"""Multiple spectators at same location all see IF output."""
|
||||||
# Create a third player at same location
|
# Create a third player at same location
|
||||||
player_d = Player(
|
writer_d = MagicMock()
|
||||||
name="PlayerD", x=5, y=5, reader=mock_reader, writer=mock_writer
|
writer_d.write = MagicMock()
|
||||||
)
|
writer_d.drain = AsyncMock()
|
||||||
|
reader_d = MagicMock()
|
||||||
|
player_d = Player(name="PlayerD", x=5, y=5, reader=reader_d, writer=writer_d)
|
||||||
|
|
||||||
# Register all players
|
# Register all players
|
||||||
players[player_a.name] = player_a
|
players[player_a.name] = player_a
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue