From 200cc00129048db304a4fefab5cf7f6043982b78 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Thu, 12 Feb 2026 16:31:17 -0500 Subject: [PATCH] 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. --- src/mudlib/gmcp.py | 23 ++++++++++++++--------- src/mudlib/player.py | 1 + tests/test_gmcp.py | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/mudlib/gmcp.py b/src/mudlib/gmcp.py index 4654d30..432a1a0 100644 --- a/src/mudlib/gmcp.py +++ b/src/mudlib/gmcp.py @@ -115,14 +115,19 @@ def send_map_data(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: return - player.send_msdp( - { - "HEALTH": str(round(player.pl, 1)), - "HEALTH_MAX": str(round(player.max_pl, 1)), - "STAMINA": str(round(player.stamina, 1)), - "STAMINA_MAX": str(round(player.max_stamina, 1)), - } - ) + data = { + "HEALTH": str(round(player.pl, 1)), + "HEALTH_MAX": str(round(player.max_pl, 1)), + "STAMINA": str(round(player.stamina, 1)), + "STAMINA_MAX": str(round(player.max_stamina, 1)), + } + if data == player._last_msdp: + return + player._last_msdp = data + player.send_msdp(data) diff --git a/src/mudlib/player.py b/src/mudlib/player.py index 558e0b0..6c242a3 100644 --- a/src/mudlib/player.py +++ b/src/mudlib/player.py @@ -30,6 +30,7 @@ class Player(Entity): paint_mode: bool = False painting: bool = False paint_brush: str = "." + _last_msdp: dict = field(default_factory=dict, repr=False) @property def mode(self) -> str: diff --git a/tests/test_gmcp.py b/tests/test_gmcp.py index fa5aafb..106aeca 100644 --- a/tests/test_gmcp.py +++ b/tests/test_gmcp.py @@ -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): """Test Player.send_gmcp convenience method.""" player.send_gmcp("Test.Package", {"key": "value"})