Dedupe MSDP vitals to avoid spamming idle clients

Cache last-sent values on Player and skip send_msdp() when
nothing changed. Idle players no longer get a packet every second.
This commit is contained in:
Jared Miller 2026-02-12 16:31:17 -05:00
parent fb758c8f36
commit 200cc00129
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
3 changed files with 30 additions and 9 deletions

View file

@ -115,14 +115,19 @@ def send_map_data(player: Player) -> None:
def send_msdp_vitals(player: Player) -> None: def send_msdp_vitals(player: Player) -> None:
"""Send MSDP variable updates for real-time gauges.""" """Send MSDP variable updates for real-time gauges.
Skips sending if values haven't changed since last send.
"""
if not player.msdp_enabled: if not player.msdp_enabled:
return return
player.send_msdp( data = {
{ "HEALTH": str(round(player.pl, 1)),
"HEALTH": str(round(player.pl, 1)), "HEALTH_MAX": str(round(player.max_pl, 1)),
"HEALTH_MAX": str(round(player.max_pl, 1)), "STAMINA": str(round(player.stamina, 1)),
"STAMINA": str(round(player.stamina, 1)), "STAMINA_MAX": str(round(player.max_stamina, 1)),
"STAMINA_MAX": str(round(player.max_stamina, 1)), }
} if data == player._last_msdp:
) return
player._last_msdp = data
player.send_msdp(data)

View file

@ -30,6 +30,7 @@ class Player(Entity):
paint_mode: bool = False paint_mode: bool = False
painting: bool = False painting: bool = False
paint_brush: str = "." paint_brush: str = "."
_last_msdp: dict = field(default_factory=dict, repr=False)
@property @property
def mode(self) -> str: def mode(self) -> str:

View file

@ -231,6 +231,21 @@ def test_send_msdp_vitals(player):
) )
def test_send_msdp_vitals_dedup(player):
"""Test MSDP skips sending when values haven't changed."""
send_msdp_vitals(player)
assert player.writer.send_msdp.call_count == 1
# second call with same values — should be suppressed
send_msdp_vitals(player)
assert player.writer.send_msdp.call_count == 1
# change a value — should send again
player.pl = 80.0
send_msdp_vitals(player)
assert player.writer.send_msdp.call_count == 2
def test_player_send_gmcp(player): def test_player_send_gmcp(player):
"""Test Player.send_gmcp convenience method.""" """Test Player.send_gmcp convenience method."""
player.send_gmcp("Test.Package", {"key": "value"}) player.send_gmcp("Test.Package", {"key": "value"})