From 43b0e36ef190b87a327301b6f97cec63a75f5b0e Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 11 Dec 2023 12:59:03 -0500 Subject: [PATCH] chat filter: cache filter results --- .../plugins/chatfilter/ChatFilterPlugin.java | 55 ++++++++++++++++--- .../chatfilter/ChatFilterPluginTest.java | 16 +++--- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java index 62696456223..20084231e12 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java @@ -32,6 +32,7 @@ import com.google.inject.Provides; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -104,7 +105,7 @@ private static class Duplicate int count; } - private final LinkedHashMap duplicateChatCache = new LinkedHashMap() + private final LinkedHashMap duplicateChatCache = new LinkedHashMap<>() { private static final int MAX_ENTRIES = 100; @@ -115,6 +116,19 @@ protected boolean removeEldestEntry(Map.Entry eldest) } }; + private static class FilterCacheMap extends LinkedHashMap + { + private static final int MAX_ENTRIES = 100; + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > MAX_ENTRIES; + } + } + + private final Map filterCache = new HashMap<>(); + @Inject private Client client; @@ -139,6 +153,8 @@ protected void shutDown() throws Exception { filteredPatterns = Collections.emptyList(); filteredNamePatterns = Collections.emptyList(); + duplicateChatCache.clear(); + filterCache.clear(); client.refreshChat(); } @@ -149,9 +165,11 @@ public void onGameStateChanged(GameStateChanged gameStateChanged) { // Login drops references to all messages and also resets the global message id counter. // Invalidate the message id so it doesn't collide later when rebuilding the chatfilter. + case CONNECTION_LOST: case HOPPING: case LOGGING_IN: duplicateChatCache.values().forEach(d -> d.messageId = -1); + filterCache.clear(); } } @@ -190,9 +208,9 @@ public void onScriptCallbackEvent(ScriptCallbackEvent event) case CLAN_CHAT: case CLAN_GUEST_CHAT: case CLAN_GIM_CHAT: - if (shouldFilterPlayerMessage(Text.removeTags(name))) + if (canFilterPlayer(Text.removeTags(name))) { - message = censorMessage(name, message); + message = censorMessageCache(messageNode, name, message); blockMessage = message == null; } break; @@ -207,7 +225,7 @@ public void onScriptCallbackEvent(ScriptCallbackEvent event) case CLAN_GIM_MESSAGE: if (config.filterGameChat()) { - message = censorMessage(null, message); + message = censorMessageCache(messageNode, null, message); blockMessage = message == null; } break; @@ -251,7 +269,7 @@ public void onScriptCallbackEvent(ScriptCallbackEvent event) @Subscribe public void onOverheadTextChanged(OverheadTextChanged event) { - if (!(event.getActor() instanceof Player) || event.getActor().getName() == null || !shouldFilterPlayerMessage(event.getActor().getName())) // NOPMD: SimplifyConditional + if (!(event.getActor() instanceof Player) || event.getActor().getName() == null || !canFilterPlayer(event.getActor().getName())) // NOPMD: SimplifyConditional { return; } @@ -286,7 +304,7 @@ public void onChatMessage(ChatMessage chatMessage) } } - boolean shouldFilterPlayerMessage(String playerName) + boolean canFilterPlayer(String playerName) { boolean isMessageFromSelf = playerName.equals(client.getLocalPlayer().getName()); return !isMessageFromSelf && @@ -327,7 +345,7 @@ String censorMessage(final String username, final String message) String strippedAccents = stripAccents(strippedMessage); assert strippedMessage.length() == strippedAccents.length(); - if (username != null && shouldFilterByName(username)) + if (username != null && isNameFiltered(username)) { switch (config.filterType()) { @@ -374,6 +392,25 @@ String censorMessage(final String username, final String message) return filtered ? strippedMessage : message; } + private String censorMessageCache(MessageNode messageNode, String username, String message) + { + FilterCacheMap map = this.filterCache.get(messageNode.getType()); + if (map == null) + { + map = new FilterCacheMap(); + this.filterCache.put(messageNode.getType(), map); + } + + if (map.containsKey(messageNode.getId())) + { + return map.get(messageNode.getId()); + } + + String censoredMessage = censorMessage(username, message); + map.put(messageNode.getId(), censoredMessage); + return censoredMessage; + } + void updateFilteredPatterns() { List patterns = new ArrayList<>(); @@ -398,6 +435,8 @@ void updateFilteredPatterns() filteredPatterns = patterns; filteredNamePatterns = namePatterns; + + filterCache.clear(); } private String stripAccents(String input) @@ -432,7 +471,7 @@ public void onConfigChanged(ConfigChanged event) } @VisibleForTesting - boolean shouldFilterByName(final String playerName) + boolean isNameFiltered(final String playerName) { String sanitizedName = Text.standardize(playerName); for (Pattern pattern : filteredNamePatterns) diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java index 318615fc430..c62e937d012 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java @@ -222,7 +222,7 @@ public void testMixedUnicodeFiltersUnicode() public void testMessageFromFriendIsFiltered() { when(chatFilterConfig.filterFriends()).thenReturn(true); - assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("Iron Mammal")); + assertTrue(chatFilterPlugin.canFilterPlayer("Iron Mammal")); } @Test @@ -230,7 +230,7 @@ public void testMessageFromFriendIsNotFiltered() { when(client.isFriended("Iron Mammal", false)).thenReturn(true); when(chatFilterConfig.filterFriends()).thenReturn(false); - assertFalse(chatFilterPlugin.shouldFilterPlayerMessage("Iron Mammal")); + assertFalse(chatFilterPlugin.canFilterPlayer("Iron Mammal")); } @Test @@ -238,7 +238,7 @@ public void testMessageFromFriendsChatIsFiltered() { when(client.isFriended("B0aty", false)).thenReturn(false); when(chatFilterConfig.filterFriendsChat()).thenReturn(true); - assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("B0aty")); + assertTrue(chatFilterPlugin.canFilterPlayer("B0aty")); } @Test @@ -246,21 +246,21 @@ public void testMessageFromFriendsChatIsNotFiltered() { when(friendsChatManager.findByName("B0aty")).thenReturn(mock(FriendsChatMember.class)); when(chatFilterConfig.filterFriendsChat()).thenReturn(false); - assertFalse(chatFilterPlugin.shouldFilterPlayerMessage("B0aty")); + assertFalse(chatFilterPlugin.canFilterPlayer("B0aty")); } @Test public void testMessageFromSelfIsNotFiltered() { when(localPlayer.getName()).thenReturn("Swampletics"); - assertFalse(chatFilterPlugin.shouldFilterPlayerMessage("Swampletics")); + assertFalse(chatFilterPlugin.canFilterPlayer("Swampletics")); } @Test public void testMessageFromNonFriendNonFCIsFiltered() { when(client.isFriended("Woox", false)).thenReturn(false); - assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("Woox")); + assertTrue(chatFilterPlugin.canFilterPlayer("Woox")); } @Test @@ -269,8 +269,8 @@ public void testShouldFilterByName() when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*"); chatFilterPlugin.updateFilteredPatterns(); - assertTrue(chatFilterPlugin.shouldFilterByName("Gamble 1234")); - assertFalse(chatFilterPlugin.shouldFilterByName("Adam")); + assertTrue(chatFilterPlugin.isNameFiltered("Gamble 1234")); + assertFalse(chatFilterPlugin.isNameFiltered("Adam")); } @Test