From 9e920945015e982b189ba0431530bd4e514106a2 Mon Sep 17 00:00:00 2001 From: Andreas Troelsen Date: Mon, 25 Jul 2022 17:30:19 +0200 Subject: [PATCH] Ignore leave events for spectators. Spectators produce leave events, but they won't have a join event that matches the leave event they produce. This is because spectators either joined _as_ spectators (spectating doesn't produce join events), or they _transitioned_ into the spectator state after _dying_ in the session (in which case they already produced a death event that "cements" the player session). This fixes an edge case problem that occurs when a spectator produces a leave event while exactly one player is currently in the lobby. In this case, the leave event triggers a session deletion, since the leave event logic "thinks" the leave event is triggered by the player in the lobby. It would be possible to prevent that problem with additional checks in the leave event logic, but the underlying problem really is that leave events produced by spectators shouldn't be recorded or reacted to in any way, shape, or form, as they are not relevant to the stats (leave times are only really relevant if the leave event happens _during_ a session, which this change does not affect). --- .../mobarena/stats/session/SessionListener.java | 4 ++++ .../stats/session/SessionListenerTest.java | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/org/mobarena/stats/session/SessionListener.java b/src/main/java/org/mobarena/stats/session/SessionListener.java index 9e3a366..f76698d 100644 --- a/src/main/java/org/mobarena/stats/session/SessionListener.java +++ b/src/main/java/org/mobarena/stats/session/SessionListener.java @@ -88,6 +88,10 @@ public class SessionListener implements Listener { Arena arena = event.getArena(); Player player = event.getPlayer(); + if (arena.inSpec(player)) { + return; + } + Session session = sessionStore.getByArena(arena); if (session == null) { log.warning("Unexpected leave event for non-existent session of arena " + arena.getSlug()); diff --git a/src/test/java/org/mobarena/stats/session/SessionListenerTest.java b/src/test/java/org/mobarena/stats/session/SessionListenerTest.java index c87f013..78ed6ef 100644 --- a/src/test/java/org/mobarena/stats/session/SessionListenerTest.java +++ b/src/test/java/org/mobarena/stats/session/SessionListenerTest.java @@ -110,10 +110,23 @@ class SessionListenerTest { verify(session).playerReady(player, className); } + @Test + void ignoresPlayerLeaveForSpectators() { + Player player = mock(Player.class); + Arena arena = mock(Arena.class); + when(arena.inSpec(player)).thenReturn(true); + ArenaPlayerLeaveEvent event = new ArenaPlayerLeaveEvent(player, arena); + + subject.on(event); + + verifyNoInteractions(sessionStore); + } + @Test void logsWarningIfPlayerLeavesInNonExistentSession() { Player player = mock(Player.class); Arena arena = mock(Arena.class); + when(arena.inSpec(player)).thenReturn(false); when(sessionStore.getByArena(arena)).thenReturn(null); ArenaPlayerLeaveEvent event = new ArenaPlayerLeaveEvent(player, arena); @@ -127,6 +140,7 @@ class SessionListenerTest { Player player = mock(Player.class); Arena arena = mock(Arena.class); Session session = mock(Session.class); + when(arena.inSpec(player)).thenReturn(false); when(arena.isRunning()).thenReturn(false); when(arena.getPlayersInLobby()).thenReturn(Collections.singleton(player)); when(sessionStore.getByArena(arena)).thenReturn(session); @@ -142,6 +156,7 @@ class SessionListenerTest { Player player = mock(Player.class); Arena arena = mock(Arena.class); Session session = mock(Session.class); + when(arena.inSpec(player)).thenReturn(false); when(arena.isRunning()).thenReturn(false); when(arena.getPlayersInLobby()).thenReturn(Collections.singleton(player)); when(sessionStore.getByArena(arena)).thenReturn(session); @@ -158,6 +173,7 @@ class SessionListenerTest { Player other = mock(Player.class); Arena arena = mock(Arena.class); Session session = mock(Session.class); + when(arena.inSpec(player)).thenReturn(false); when(arena.isRunning()).thenReturn(false); when(arena.getPlayersInLobby()).thenReturn(new HashSet<>(Arrays.asList(player, other))); when(sessionStore.getByArena(arena)).thenReturn(session); @@ -173,6 +189,7 @@ class SessionListenerTest { Player player = mock(Player.class); Arena arena = mock(Arena.class); Session session = mock(Session.class); + when(arena.inSpec(player)).thenReturn(false); when(arena.isRunning()).thenReturn(true); when(sessionStore.getByArena(arena)).thenReturn(session); ArenaPlayerLeaveEvent event = new ArenaPlayerLeaveEvent(player, arena);