Repository: pajlads/DinkPlugin (java)

Issue:
Loot: Have rarity override respect denylist
### Checklist

- [X] I've searched the [issues and pull requests](https://github.com/pajlads/Dinkplugin/issues?q=) for similar looking suggestions.
- [X] I've checked the `Unreleased` section of the [changelog](https://github.com/pajlads/DinkPlugin/blob/master/CHANGELOG.md) for newly added features that sound like my suggestion.

### Describe your Suggestion

No longer sends notifications for filtered items just because they're rare.

### Reasoning

Enemy loot tables are a lot of the time filled with rare, but otherwise uninteresting seeds/herbs

Pull request:
fix: exclude deny listed loot from rarity override
Closes #446


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d1369d3..a07328c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
 ## Unreleased
 
 - Major: Add notifier for chat messages that match custom patterns. (#391)
+- Bugfix: Exclude denylisted items from loot rarity override consideration. (#447)
 
 ## 1.9.1
 
diff --git a/src/main/java/dinkplugin/DinkPluginConfig.java b/src/main/java/dinkplugin/DinkPluginConfig.java
index eac84b8..79508a2 100644
--- a/src/main/java/dinkplugin/DinkPluginConfig.java
+++ b/src/main/java/dinkplugin/DinkPluginConfig.java
@@ -897,7 +897,7 @@ public interface DinkPluginConfig extends Config {
     @ConfigItem(
         keyName = "lootItemDenylist",
         name = "Item Denylist",
-        description = "Never fire notifications for these items, despite value settings.<br/>" +
+        description = "Never fire notifications for these items, despite value or rarity settings.<br/>" +
             "Place one item name per line (case-insensitive; asterisks are wildcards)",
         position = 37,
         section = lootSection
diff --git a/src/main/java/dinkplugin/notifiers/LootNotifier.java b/src/main/java/dinkplugin/notifiers/LootNotifier.java
index ec8787f..3e4cc82 100644
--- a/src/main/java/dinkplugin/notifiers/LootNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/LootNotifier.java
@@ -35,6 +35,7 @@ import javax.inject.Singleton;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -155,6 +156,7 @@ public class LootNotifier extends BaseNotifier {
         long totalStackValue = 0;
         boolean sendMessage = false;
         SerializedItemStack max = null;
+        Collection<Integer> deniedIds = new HashSet<>(reduced.size());
 
         for (ItemStack item : reduced) {
             SerializedItemStack stack = ItemUtils.stackFromItem(itemManager, item.getId(), item.getQuantity());
@@ -169,12 +171,14 @@ public class LootNotifier extends BaseNotifier {
                 if (max == null || totalPrice > max.getTotalPrice()) {
                     max = stack;
                 }
+            } else {
+                deniedIds.add(item.getId());
             }
             serializedItems.add(stack);
             totalStackValue += totalPrice;
         }
 
-        Map.Entry<SerializedItemStack, Double> rarest = getRarestDropRate(items, dropper, type);
+        Map.Entry<SerializedItemStack, Double> rarest = getRarestDropRate(items, dropper, type, deniedIds);
 
         Evaluable lootMsg;
         if (!sendMessage) {
@@ -234,9 +238,10 @@ public class LootNotifier extends BaseNotifier {
     }
 
     @Nullable
-    private Map.Entry<SerializedItemStack, Double> getRarestDropRate(Collection<ItemStack> items, String dropper, LootRecordType type) {
+    private Map.Entry<SerializedItemStack, Double> getRarestDropRate(Collection<ItemStack> items, String dropper, LootRecordType type, Collection<Integer> deniedIds) {
         if (type != LootRecordType.NPC) return null;
         return items.stream()
+            .filter(item -> !deniedIds.contains(item.getId()))
             .map(item -> {
                 OptionalDouble rarity = rarityService.getRarity(dropper, item.getId(), item.getQuantity());
                 if (rarity.isEmpty()) return null;


Test patch:
diff --git a/src/test/java/dinkplugin/notifiers/LootNotifierTest.java b/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
index e2184cd..bb4d719 100644
--- a/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
+++ b/src/test/java/dinkplugin/notifiers/LootNotifierTest.java
@@ -168,6 +168,27 @@ class LootNotifierTest extends MockedNotifierTest {
         verify(messageHandler, never()).createMessage(any(), anyBoolean(), any());
     }
 
+    @Test // https://github.com/pajlads/DinkPlugin/issues/446
+    void testIgnoreRarityDenyList() {
+        // update config mocks
+        when(config.minLootValue()).thenReturn(LARRAN_PRICE + 1);
+        when(config.lootRarityThreshold()).thenReturn(100);
+        notifier.onConfigChanged("lootItemDenylist", "Larran's key");
+
+        // prepare mocks
+        NPC npc = mock(NPC.class);
+        String name = "Ice spider";
+        when(npc.getName()).thenReturn(name);
+
+        // fire event
+        double rarity = 1.0 / 208;
+        NpcLootReceived event = new NpcLootReceived(npc, List.of(new ItemStack(ItemID.LARRANS_KEY, 1, null)));
+        plugin.onNpcLootReceived(event);
+
+        // ensure no notification
+        verify(messageHandler, never()).createMessage(any(), anyBoolean(), any());
+    }
+
     @Test
     void testNotifyAllowlist() {
         // prepare mocks