diff --git a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java index fc945220f1..01e180c55b 100644 --- a/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java +++ b/http-api/src/main/java/net/runelite/http/api/loottracker/LootRecord.java @@ -37,6 +37,7 @@ public class LootRecord { private String eventId; private LootRecordType type; + private Object metadata; private Collection drops; private Instant time; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index 0d0462e4a1..0641f74e44 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -70,6 +70,7 @@ import net.runelite.api.MessageNode; import net.runelite.api.NPC; import net.runelite.api.ObjectID; import net.runelite.api.Player; +import net.runelite.api.Skill; import net.runelite.api.SpriteID; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; @@ -256,6 +257,7 @@ public class LootTrackerPlugin extends Plugin String eventType; @VisibleForTesting LootRecordType lootRecordType; + private Object metadata; private boolean chestLooted; private String lastPickpocketTarget; @@ -427,14 +429,14 @@ public class LootTrackerPlugin extends Plugin } } - void addLoot(@NonNull String name, int combatLevel, LootRecordType type, Collection items) + void addLoot(@NonNull String name, int combatLevel, LootRecordType type, Object metadata, Collection items) { final LootTrackerItem[] entries = buildEntries(stack(items)); SwingUtilities.invokeLater(() -> panel.add(name, type, combatLevel, entries)); if (config.saveLoot()) { - LootRecord lootRecord = new LootRecord(name, type, toGameItems(items), Instant.now()); + LootRecord lootRecord = new LootRecord(name, type, metadata, toGameItems(items), Instant.now()); synchronized (queuedLoots) { queuedLoots.add(lootRecord); @@ -452,7 +454,7 @@ public class LootTrackerPlugin extends Plugin final String name = npc.getName(); final int combat = npc.getCombatLevel(); - addLoot(name, combat, LootRecordType.NPC, items); + addLoot(name, combat, LootRecordType.NPC, npc.getId(), items); if (config.npcKillChatMessage()) { @@ -478,7 +480,7 @@ public class LootTrackerPlugin extends Plugin final String name = player.getName(); final int combat = player.getCombatLevel(); - addLoot(name, combat, LootRecordType.PLAYER, items); + addLoot(name, combat, LootRecordType.PLAYER, null, items); if (config.pvpKillChatMessage()) { @@ -489,12 +491,12 @@ public class LootTrackerPlugin extends Plugin @Subscribe public void onWidgetLoaded(WidgetLoaded widgetLoaded) { - final String event; final ItemContainer container; + switch (widgetLoaded.getGroupId()) { case (WidgetID.BARROWS_REWARD_GROUP_ID): - event = "Barrows"; + setEvent(LootRecordType.EVENT, "Barrows"); container = client.getItemContainer(InventoryID.BARROWS_REWARD); break; case (WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID): @@ -502,7 +504,7 @@ public class LootTrackerPlugin extends Plugin { return; } - event = "Chambers of Xeric"; + setEvent(LootRecordType.EVENT, "Chambers of Xeric"); container = client.getItemContainer(InventoryID.CHAMBERS_OF_XERIC_CHEST); chestLooted = true; break; @@ -516,32 +518,31 @@ public class LootTrackerPlugin extends Plugin { return; } - event = "Theatre of Blood"; + setEvent(LootRecordType.EVENT, "Theatre of Blood"); container = client.getItemContainer(InventoryID.THEATRE_OF_BLOOD_CHEST); chestLooted = true; break; case (WidgetID.CLUE_SCROLL_REWARD_GROUP_ID): // event type should be set via ChatMessage for clue scrolls. // Clue Scrolls use same InventoryID as Barrows - event = eventType; container = client.getItemContainer(InventoryID.BARROWS_REWARD); - if (event == null) + if (eventType == null) { log.debug("Clue scroll reward interface with no event!"); return; } break; case (WidgetID.KINGDOM_GROUP_ID): - event = "Kingdom of Miscellania"; + setEvent(LootRecordType.EVENT, "Kingdom of Miscellania"); container = client.getItemContainer(InventoryID.KINGDOM_OF_MISCELLANIA); break; case (WidgetID.FISHING_TRAWLER_REWARD_GROUP_ID): - event = "Fishing Trawler"; + setEvent(LootRecordType.EVENT, "Fishing Trawler", client.getBoostedSkillLevel(Skill.FISHING)); container = client.getItemContainer(InventoryID.FISHING_TRAWLER_REWARD); break; case (WidgetID.DRIFT_NET_FISHING_REWARD_GROUP_ID): - event = "Drift Net"; + setEvent(LootRecordType.EVENT, "Drift Net", client.getBoostedSkillLevel(Skill.FISHING)); container = client.getItemContainer(InventoryID.DRIFT_NET_FISHING_REWARD); break; default: @@ -559,7 +560,7 @@ public class LootTrackerPlugin extends Plugin .map(item -> new ItemStack(item.getId(), item.getQuantity(), client.getLocalPlayer().getLocalLocation())) .collect(Collectors.toList()); - if (config.showRaidsLootValue() && (event.equals("Theatre of Blood") || event.equals("Chambers of Xeric"))) + if (config.showRaidsLootValue() && (eventType.equals("Theatre of Blood") || eventType.equals("Chambers of Xeric"))) { long totalValue = items.stream() .filter(item -> item.getId() > -1) @@ -585,11 +586,11 @@ public class LootTrackerPlugin extends Plugin if (items.isEmpty()) { - log.debug("No items to find for Event: {} | Container: {}", event, container); + log.debug("No items to find for Event: {} | Container: {}", eventType, container); return; } - addLoot(event, -1, LootRecordType.EVENT, items); + addLoot(eventType, -1, lootRecordType, metadata, items); } @Subscribe @@ -612,8 +613,7 @@ public class LootTrackerPlugin extends Plugin return; } - eventType = CHEST_EVENT_TYPES.get(regionID); - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, CHEST_EVENT_TYPES.get(regionID)); takeInventorySnapshot(); return; @@ -622,8 +622,7 @@ public class LootTrackerPlugin extends Plugin if (message.equals(COFFIN_LOOTED_MESSAGE) && isPlayerWithinMapRegion(HALLOWED_SEPULCHRE_MAP_REGIONS)) { - eventType = HALLOWED_SEPULCHRE_COFFIN_EVENT; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, HALLOWED_SEPULCHRE_COFFIN_EVENT); takeInventorySnapshot(); return; } @@ -635,8 +634,7 @@ public class LootTrackerPlugin extends Plugin return; } - eventType = HERBIBOAR_EVENT; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, HERBIBOAR_EVENT, client.getBoostedSkillLevel(Skill.HERBLORE)); takeInventorySnapshot(); return; } @@ -644,8 +642,7 @@ public class LootTrackerPlugin extends Plugin final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID(); if (HESPORI_REGION == regionID && message.equals(HESPORI_LOOTED_MESSAGE)) { - eventType = HESPORI_EVENT; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, HESPORI_EVENT); takeInventorySnapshot(); return; } @@ -654,8 +651,7 @@ public class LootTrackerPlugin extends Plugin if (hamStoreroomMatcher.matches() && regionID == HAM_STOREROOM_REGION) { String keyType = hamStoreroomMatcher.group("key"); - eventType = String.format("H.A.M. chest (%s)", keyType); - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, String.format("H.A.M. chest (%s)", keyType)); takeInventorySnapshot(); return; } @@ -669,13 +665,11 @@ public class LootTrackerPlugin extends Plugin // Occasional edge case where the pickpocket message doesn't list the correct name of the NPC (e.g. H.A.M. Members) if (PICKPOCKET_DISAMBIGUATION_MAP.get(lastPickpocketTarget).contains(pickpocketTarget)) { - eventType = lastPickpocketTarget; - lootRecordType = LootRecordType.PICKPOCKET; + setEvent(LootRecordType.PICKPOCKET, lastPickpocketTarget); } else { - eventType = pickpocketTarget; - lootRecordType = LootRecordType.PICKPOCKET; + setEvent(LootRecordType.PICKPOCKET, pickpocketTarget); } takeInventorySnapshot(); @@ -690,28 +684,22 @@ public class LootTrackerPlugin extends Plugin switch (type) { case "beginner": - eventType = "Clue Scroll (Beginner)"; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, "Clue Scroll (Beginner)"); return; case "easy": - eventType = "Clue Scroll (Easy)"; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, "Clue Scroll (Easy)"); return; case "medium": - eventType = "Clue Scroll (Medium)"; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, "Clue Scroll (Medium)"); return; case "hard": - eventType = "Clue Scroll (Hard)"; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, "Clue Scroll (Hard)"); return; case "elite": - eventType = "Clue Scroll (Elite)"; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, "Clue Scroll (Elite)"); return; case "master": - eventType = "Clue Scroll (Master)"; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, "Clue Scroll (Master)"); return; } } @@ -719,8 +707,7 @@ public class LootTrackerPlugin extends Plugin if (SHADE_CHEST_NO_KEY_PATTERN.matcher(message).matches()) { // Player didn't have the key they needed. - eventType = null; - lootRecordType = null; + resetEvent(); } } @@ -747,9 +734,8 @@ public class LootTrackerPlugin extends Plugin WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); Collection groundItems = lootManager.getItemSpawns(playerLocation); - processInventoryLoot(eventType, lootRecordType, event.getItemContainer(), groundItems); - eventType = null; - lootRecordType = null; + processInventoryLoot(eventType, lootRecordType, metadata, event.getItemContainer(), groundItems); + resetEvent(); } } @@ -765,29 +751,25 @@ public class LootTrackerPlugin extends Plugin if (event.getMenuOption().equals("Take") && event.getId() == ItemID.SEED_PACK) { - eventType = SEEDPACK_EVENT; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, SEEDPACK_EVENT); takeInventorySnapshot(); } if (event.getMenuOption().equals("Open") && SHADE_CHEST_OBJECTS.containsKey(event.getId())) { - eventType = SHADE_CHEST_OBJECTS.get(event.getId()); - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, SHADE_CHEST_OBJECTS.get(event.getId())); takeInventorySnapshot(); } if (event.getMenuOption().equals("Search") && BIRDNEST_IDS.contains(event.getId())) { - eventType = BIRDNEST_EVENT; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, BIRDNEST_EVENT); takeInventorySnapshot(); } if (event.getMenuOption().equals("Open") && event.getId() == ItemID.CASKET) { - eventType = CASKET_EVENT; - lootRecordType = LootRecordType.EVENT; + setEvent(LootRecordType.EVENT, CASKET_EVENT); takeInventorySnapshot(); } } @@ -828,6 +810,25 @@ public class LootTrackerPlugin extends Plugin return future; } + private void setEvent(LootRecordType lootRecordType, String eventType, Object metadata) + { + this.lootRecordType = lootRecordType; + this.eventType = eventType; + this.metadata = metadata; + } + + private void setEvent(LootRecordType lootRecordType, String eventType) + { + setEvent(lootRecordType, eventType, null); + } + + private void resetEvent() + { + lootRecordType = null; + eventType = null; + metadata = null; + } + private void takeInventorySnapshot() { final ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY); @@ -839,7 +840,7 @@ public class LootTrackerPlugin extends Plugin } } - private void processInventoryLoot(String event, LootRecordType lootRecordType, ItemContainer inventoryContainer, Collection groundItems) + private void processInventoryLoot(String event, LootRecordType lootRecordType, Object metadata, ItemContainer inventoryContainer, Collection groundItems) { if (inventorySnapshot != null) { @@ -856,7 +857,7 @@ public class LootTrackerPlugin extends Plugin .map(e -> new ItemStack(e.getElement(), e.getCount(), client.getLocalPlayer().getLocalLocation())) .collect(Collectors.toList()); - addLoot(event, -1, lootRecordType, items); + addLoot(event, -1, lootRecordType, metadata, items); inventorySnapshot = null; } @@ -886,7 +887,8 @@ public class LootTrackerPlugin extends Plugin return false; } - addLoot(HERBIBOAR_EVENT, -1, LootRecordType.EVENT, herbs); + int herbloreLevel = client.getBoostedSkillLevel(Skill.HERBLORE); + addLoot(HERBIBOAR_EVENT, -1, LootRecordType.EVENT, herbloreLevel, herbs); return true; } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java index 4b74201060..12f6e4d990 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java @@ -45,6 +45,7 @@ import net.runelite.api.ItemID; import net.runelite.api.IterableHashTable; import net.runelite.api.MessageNode; import net.runelite.api.Player; +import net.runelite.api.Skill; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; @@ -69,6 +70,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; import org.mockito.Mock; import org.mockito.Mockito; import static org.mockito.Mockito.doNothing; @@ -172,6 +174,8 @@ public class LootTrackerPluginTest @Test public void testHerbiboarHerbSack() { + when(client.getBoostedSkillLevel(Skill.HERBLORE)).thenReturn(42); + for (Map.Entry herb : HERB_IDS_TO_NAMES.entrySet()) { final int id = herb.getKey(); @@ -200,12 +204,12 @@ public class LootTrackerPluginTest when(client.getMessages()).thenReturn(messageTable); LootTrackerPlugin lootTrackerPluginSpy = spy(this.lootTrackerPlugin); - doNothing().when(lootTrackerPluginSpy).addLoot(any(), anyInt(), any(), any(Collection.class)); + doNothing().when(lootTrackerPluginSpy).addLoot(any(), anyInt(), any(), any(), any(Collection.class)); ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", LootTrackerPlugin.HERBIBOAR_LOOTED_MESSAGE, "", 0); lootTrackerPluginSpy.onChatMessage(chatMessage); - verify(lootTrackerPluginSpy).addLoot("Herbiboar", -1, LootRecordType.EVENT, Arrays.asList( + verify(lootTrackerPluginSpy).addLoot("Herbiboar", -1, LootRecordType.EVENT, 42, Arrays.asList( new ItemStack(id, 1, null), new ItemStack(id, 1, null) )); @@ -222,7 +226,7 @@ public class LootTrackerPluginTest LootTrackerPlugin spyPlugin = Mockito.spy(lootTrackerPlugin); // Make sure we don't execute addLoot, so we don't have to mock LootTrackerPanel and everything else also - doNothing().when(spyPlugin).addLoot(anyString(), anyInt(), any(LootRecordType.class), anyCollection()); + doNothing().when(spyPlugin).addLoot(anyString(), anyInt(), any(LootRecordType.class), isNull(), anyCollection()); ItemContainer itemContainer = mock(ItemContainer.class); when(itemContainer.getItems()).thenReturn(new Item[]{ @@ -253,7 +257,7 @@ public class LootTrackerPluginTest LootTrackerPlugin spyPlugin = Mockito.spy(lootTrackerPlugin); // Make sure we don't execute addLoot, so we don't have to mock LootTrackerPanel and everything else also - doNothing().when(spyPlugin).addLoot(anyString(), anyInt(), any(LootRecordType.class), anyCollection()); + doNothing().when(spyPlugin).addLoot(anyString(), anyInt(), any(LootRecordType.class), isNull(), anyCollection()); ItemContainer itemContainer = mock(ItemContainer.class); when(itemContainer.getItems()).thenReturn(new Item[]{