loot tracker: add metadata field to loot record

This is for tracking miscellaneous data with the loot records, such as
npc id and skill levels, for the wiki drop log project.

Co-authored-by: Adam <Adam@sigterm.info>
This commit is contained in:
leejt
2020-08-07 14:26:37 -04:00
committed by Adam
parent 7affadcf50
commit 18087ca9cc
3 changed files with 69 additions and 62 deletions

View File

@@ -37,6 +37,7 @@ public class LootRecord
{ {
private String eventId; private String eventId;
private LootRecordType type; private LootRecordType type;
private Object metadata;
private Collection<GameItem> drops; private Collection<GameItem> drops;
private Instant time; private Instant time;
} }

View File

@@ -70,6 +70,7 @@ import net.runelite.api.MessageNode;
import net.runelite.api.NPC; import net.runelite.api.NPC;
import net.runelite.api.ObjectID; import net.runelite.api.ObjectID;
import net.runelite.api.Player; import net.runelite.api.Player;
import net.runelite.api.Skill;
import net.runelite.api.SpriteID; import net.runelite.api.SpriteID;
import net.runelite.api.coords.WorldPoint; import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ChatMessage;
@@ -256,6 +257,7 @@ public class LootTrackerPlugin extends Plugin
String eventType; String eventType;
@VisibleForTesting @VisibleForTesting
LootRecordType lootRecordType; LootRecordType lootRecordType;
private Object metadata;
private boolean chestLooted; private boolean chestLooted;
private String lastPickpocketTarget; private String lastPickpocketTarget;
@@ -427,14 +429,14 @@ public class LootTrackerPlugin extends Plugin
} }
} }
void addLoot(@NonNull String name, int combatLevel, LootRecordType type, Collection<ItemStack> items) void addLoot(@NonNull String name, int combatLevel, LootRecordType type, Object metadata, Collection<ItemStack> items)
{ {
final LootTrackerItem[] entries = buildEntries(stack(items)); final LootTrackerItem[] entries = buildEntries(stack(items));
SwingUtilities.invokeLater(() -> panel.add(name, type, combatLevel, entries)); SwingUtilities.invokeLater(() -> panel.add(name, type, combatLevel, entries));
if (config.saveLoot()) 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) synchronized (queuedLoots)
{ {
queuedLoots.add(lootRecord); queuedLoots.add(lootRecord);
@@ -452,7 +454,7 @@ public class LootTrackerPlugin extends Plugin
final String name = npc.getName(); final String name = npc.getName();
final int combat = npc.getCombatLevel(); final int combat = npc.getCombatLevel();
addLoot(name, combat, LootRecordType.NPC, items); addLoot(name, combat, LootRecordType.NPC, npc.getId(), items);
if (config.npcKillChatMessage()) if (config.npcKillChatMessage())
{ {
@@ -478,7 +480,7 @@ public class LootTrackerPlugin extends Plugin
final String name = player.getName(); final String name = player.getName();
final int combat = player.getCombatLevel(); final int combat = player.getCombatLevel();
addLoot(name, combat, LootRecordType.PLAYER, items); addLoot(name, combat, LootRecordType.PLAYER, null, items);
if (config.pvpKillChatMessage()) if (config.pvpKillChatMessage())
{ {
@@ -489,12 +491,12 @@ public class LootTrackerPlugin extends Plugin
@Subscribe @Subscribe
public void onWidgetLoaded(WidgetLoaded widgetLoaded) public void onWidgetLoaded(WidgetLoaded widgetLoaded)
{ {
final String event;
final ItemContainer container; final ItemContainer container;
switch (widgetLoaded.getGroupId()) switch (widgetLoaded.getGroupId())
{ {
case (WidgetID.BARROWS_REWARD_GROUP_ID): case (WidgetID.BARROWS_REWARD_GROUP_ID):
event = "Barrows"; setEvent(LootRecordType.EVENT, "Barrows");
container = client.getItemContainer(InventoryID.BARROWS_REWARD); container = client.getItemContainer(InventoryID.BARROWS_REWARD);
break; break;
case (WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID): case (WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID):
@@ -502,7 +504,7 @@ public class LootTrackerPlugin extends Plugin
{ {
return; return;
} }
event = "Chambers of Xeric"; setEvent(LootRecordType.EVENT, "Chambers of Xeric");
container = client.getItemContainer(InventoryID.CHAMBERS_OF_XERIC_CHEST); container = client.getItemContainer(InventoryID.CHAMBERS_OF_XERIC_CHEST);
chestLooted = true; chestLooted = true;
break; break;
@@ -516,32 +518,31 @@ public class LootTrackerPlugin extends Plugin
{ {
return; return;
} }
event = "Theatre of Blood"; setEvent(LootRecordType.EVENT, "Theatre of Blood");
container = client.getItemContainer(InventoryID.THEATRE_OF_BLOOD_CHEST); container = client.getItemContainer(InventoryID.THEATRE_OF_BLOOD_CHEST);
chestLooted = true; chestLooted = true;
break; break;
case (WidgetID.CLUE_SCROLL_REWARD_GROUP_ID): case (WidgetID.CLUE_SCROLL_REWARD_GROUP_ID):
// event type should be set via ChatMessage for clue scrolls. // event type should be set via ChatMessage for clue scrolls.
// Clue Scrolls use same InventoryID as Barrows // Clue Scrolls use same InventoryID as Barrows
event = eventType;
container = client.getItemContainer(InventoryID.BARROWS_REWARD); container = client.getItemContainer(InventoryID.BARROWS_REWARD);
if (event == null) if (eventType == null)
{ {
log.debug("Clue scroll reward interface with no event!"); log.debug("Clue scroll reward interface with no event!");
return; return;
} }
break; break;
case (WidgetID.KINGDOM_GROUP_ID): case (WidgetID.KINGDOM_GROUP_ID):
event = "Kingdom of Miscellania"; setEvent(LootRecordType.EVENT, "Kingdom of Miscellania");
container = client.getItemContainer(InventoryID.KINGDOM_OF_MISCELLANIA); container = client.getItemContainer(InventoryID.KINGDOM_OF_MISCELLANIA);
break; break;
case (WidgetID.FISHING_TRAWLER_REWARD_GROUP_ID): 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); container = client.getItemContainer(InventoryID.FISHING_TRAWLER_REWARD);
break; break;
case (WidgetID.DRIFT_NET_FISHING_REWARD_GROUP_ID): 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); container = client.getItemContainer(InventoryID.DRIFT_NET_FISHING_REWARD);
break; break;
default: default:
@@ -559,7 +560,7 @@ public class LootTrackerPlugin extends Plugin
.map(item -> new ItemStack(item.getId(), item.getQuantity(), client.getLocalPlayer().getLocalLocation())) .map(item -> new ItemStack(item.getId(), item.getQuantity(), client.getLocalPlayer().getLocalLocation()))
.collect(Collectors.toList()); .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() long totalValue = items.stream()
.filter(item -> item.getId() > -1) .filter(item -> item.getId() > -1)
@@ -585,11 +586,11 @@ public class LootTrackerPlugin extends Plugin
if (items.isEmpty()) 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; return;
} }
addLoot(event, -1, LootRecordType.EVENT, items); addLoot(eventType, -1, lootRecordType, metadata, items);
} }
@Subscribe @Subscribe
@@ -612,8 +613,7 @@ public class LootTrackerPlugin extends Plugin
return; return;
} }
eventType = CHEST_EVENT_TYPES.get(regionID); setEvent(LootRecordType.EVENT, CHEST_EVENT_TYPES.get(regionID));
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
return; return;
@@ -622,8 +622,7 @@ public class LootTrackerPlugin extends Plugin
if (message.equals(COFFIN_LOOTED_MESSAGE) && if (message.equals(COFFIN_LOOTED_MESSAGE) &&
isPlayerWithinMapRegion(HALLOWED_SEPULCHRE_MAP_REGIONS)) isPlayerWithinMapRegion(HALLOWED_SEPULCHRE_MAP_REGIONS))
{ {
eventType = HALLOWED_SEPULCHRE_COFFIN_EVENT; setEvent(LootRecordType.EVENT, HALLOWED_SEPULCHRE_COFFIN_EVENT);
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
return; return;
} }
@@ -635,8 +634,7 @@ public class LootTrackerPlugin extends Plugin
return; return;
} }
eventType = HERBIBOAR_EVENT; setEvent(LootRecordType.EVENT, HERBIBOAR_EVENT, client.getBoostedSkillLevel(Skill.HERBLORE));
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
return; return;
} }
@@ -644,8 +642,7 @@ public class LootTrackerPlugin extends Plugin
final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID(); final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID();
if (HESPORI_REGION == regionID && message.equals(HESPORI_LOOTED_MESSAGE)) if (HESPORI_REGION == regionID && message.equals(HESPORI_LOOTED_MESSAGE))
{ {
eventType = HESPORI_EVENT; setEvent(LootRecordType.EVENT, HESPORI_EVENT);
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
return; return;
} }
@@ -654,8 +651,7 @@ public class LootTrackerPlugin extends Plugin
if (hamStoreroomMatcher.matches() && regionID == HAM_STOREROOM_REGION) if (hamStoreroomMatcher.matches() && regionID == HAM_STOREROOM_REGION)
{ {
String keyType = hamStoreroomMatcher.group("key"); String keyType = hamStoreroomMatcher.group("key");
eventType = String.format("H.A.M. chest (%s)", keyType); setEvent(LootRecordType.EVENT, String.format("H.A.M. chest (%s)", keyType));
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
return; 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) // 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)) if (PICKPOCKET_DISAMBIGUATION_MAP.get(lastPickpocketTarget).contains(pickpocketTarget))
{ {
eventType = lastPickpocketTarget; setEvent(LootRecordType.PICKPOCKET, lastPickpocketTarget);
lootRecordType = LootRecordType.PICKPOCKET;
} }
else else
{ {
eventType = pickpocketTarget; setEvent(LootRecordType.PICKPOCKET, pickpocketTarget);
lootRecordType = LootRecordType.PICKPOCKET;
} }
takeInventorySnapshot(); takeInventorySnapshot();
@@ -690,28 +684,22 @@ public class LootTrackerPlugin extends Plugin
switch (type) switch (type)
{ {
case "beginner": case "beginner":
eventType = "Clue Scroll (Beginner)"; setEvent(LootRecordType.EVENT, "Clue Scroll (Beginner)");
lootRecordType = LootRecordType.EVENT;
return; return;
case "easy": case "easy":
eventType = "Clue Scroll (Easy)"; setEvent(LootRecordType.EVENT, "Clue Scroll (Easy)");
lootRecordType = LootRecordType.EVENT;
return; return;
case "medium": case "medium":
eventType = "Clue Scroll (Medium)"; setEvent(LootRecordType.EVENT, "Clue Scroll (Medium)");
lootRecordType = LootRecordType.EVENT;
return; return;
case "hard": case "hard":
eventType = "Clue Scroll (Hard)"; setEvent(LootRecordType.EVENT, "Clue Scroll (Hard)");
lootRecordType = LootRecordType.EVENT;
return; return;
case "elite": case "elite":
eventType = "Clue Scroll (Elite)"; setEvent(LootRecordType.EVENT, "Clue Scroll (Elite)");
lootRecordType = LootRecordType.EVENT;
return; return;
case "master": case "master":
eventType = "Clue Scroll (Master)"; setEvent(LootRecordType.EVENT, "Clue Scroll (Master)");
lootRecordType = LootRecordType.EVENT;
return; return;
} }
} }
@@ -719,8 +707,7 @@ public class LootTrackerPlugin extends Plugin
if (SHADE_CHEST_NO_KEY_PATTERN.matcher(message).matches()) if (SHADE_CHEST_NO_KEY_PATTERN.matcher(message).matches())
{ {
// Player didn't have the key they needed. // Player didn't have the key they needed.
eventType = null; resetEvent();
lootRecordType = null;
} }
} }
@@ -747,9 +734,8 @@ public class LootTrackerPlugin extends Plugin
WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation();
Collection<ItemStack> groundItems = lootManager.getItemSpawns(playerLocation); Collection<ItemStack> groundItems = lootManager.getItemSpawns(playerLocation);
processInventoryLoot(eventType, lootRecordType, event.getItemContainer(), groundItems); processInventoryLoot(eventType, lootRecordType, metadata, event.getItemContainer(), groundItems);
eventType = null; resetEvent();
lootRecordType = null;
} }
} }
@@ -765,29 +751,25 @@ public class LootTrackerPlugin extends Plugin
if (event.getMenuOption().equals("Take") && event.getId() == ItemID.SEED_PACK) if (event.getMenuOption().equals("Take") && event.getId() == ItemID.SEED_PACK)
{ {
eventType = SEEDPACK_EVENT; setEvent(LootRecordType.EVENT, SEEDPACK_EVENT);
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
} }
if (event.getMenuOption().equals("Open") && SHADE_CHEST_OBJECTS.containsKey(event.getId())) if (event.getMenuOption().equals("Open") && SHADE_CHEST_OBJECTS.containsKey(event.getId()))
{ {
eventType = SHADE_CHEST_OBJECTS.get(event.getId()); setEvent(LootRecordType.EVENT, SHADE_CHEST_OBJECTS.get(event.getId()));
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
} }
if (event.getMenuOption().equals("Search") && BIRDNEST_IDS.contains(event.getId())) if (event.getMenuOption().equals("Search") && BIRDNEST_IDS.contains(event.getId()))
{ {
eventType = BIRDNEST_EVENT; setEvent(LootRecordType.EVENT, BIRDNEST_EVENT);
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
} }
if (event.getMenuOption().equals("Open") && event.getId() == ItemID.CASKET) if (event.getMenuOption().equals("Open") && event.getId() == ItemID.CASKET)
{ {
eventType = CASKET_EVENT; setEvent(LootRecordType.EVENT, CASKET_EVENT);
lootRecordType = LootRecordType.EVENT;
takeInventorySnapshot(); takeInventorySnapshot();
} }
} }
@@ -828,6 +810,25 @@ public class LootTrackerPlugin extends Plugin
return future; 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() private void takeInventorySnapshot()
{ {
final ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY); 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<ItemStack> groundItems) private void processInventoryLoot(String event, LootRecordType lootRecordType, Object metadata, ItemContainer inventoryContainer, Collection<ItemStack> groundItems)
{ {
if (inventorySnapshot != null) if (inventorySnapshot != null)
{ {
@@ -856,7 +857,7 @@ public class LootTrackerPlugin extends Plugin
.map(e -> new ItemStack(e.getElement(), e.getCount(), client.getLocalPlayer().getLocalLocation())) .map(e -> new ItemStack(e.getElement(), e.getCount(), client.getLocalPlayer().getLocalLocation()))
.collect(Collectors.toList()); .collect(Collectors.toList());
addLoot(event, -1, lootRecordType, items); addLoot(event, -1, lootRecordType, metadata, items);
inventorySnapshot = null; inventorySnapshot = null;
} }
@@ -886,7 +887,8 @@ public class LootTrackerPlugin extends Plugin
return false; 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; return true;
} }

View File

@@ -45,6 +45,7 @@ import net.runelite.api.ItemID;
import net.runelite.api.IterableHashTable; import net.runelite.api.IterableHashTable;
import net.runelite.api.MessageNode; import net.runelite.api.MessageNode;
import net.runelite.api.Player; import net.runelite.api.Player;
import net.runelite.api.Skill;
import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint; import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ChatMessage; 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.anyCollection;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isNull;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
@@ -172,6 +174,8 @@ public class LootTrackerPluginTest
@Test @Test
public void testHerbiboarHerbSack() public void testHerbiboarHerbSack()
{ {
when(client.getBoostedSkillLevel(Skill.HERBLORE)).thenReturn(42);
for (Map.Entry<Integer, String> herb : HERB_IDS_TO_NAMES.entrySet()) for (Map.Entry<Integer, String> herb : HERB_IDS_TO_NAMES.entrySet())
{ {
final int id = herb.getKey(); final int id = herb.getKey();
@@ -200,12 +204,12 @@ public class LootTrackerPluginTest
when(client.getMessages()).thenReturn(messageTable); when(client.getMessages()).thenReturn(messageTable);
LootTrackerPlugin lootTrackerPluginSpy = spy(this.lootTrackerPlugin); 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); ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", LootTrackerPlugin.HERBIBOAR_LOOTED_MESSAGE, "", 0);
lootTrackerPluginSpy.onChatMessage(chatMessage); 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),
new ItemStack(id, 1, null) new ItemStack(id, 1, null)
)); ));
@@ -222,7 +226,7 @@ public class LootTrackerPluginTest
LootTrackerPlugin spyPlugin = Mockito.spy(lootTrackerPlugin); LootTrackerPlugin spyPlugin = Mockito.spy(lootTrackerPlugin);
// Make sure we don't execute addLoot, so we don't have to mock LootTrackerPanel and everything else also // 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); ItemContainer itemContainer = mock(ItemContainer.class);
when(itemContainer.getItems()).thenReturn(new Item[]{ when(itemContainer.getItems()).thenReturn(new Item[]{
@@ -253,7 +257,7 @@ public class LootTrackerPluginTest
LootTrackerPlugin spyPlugin = Mockito.spy(lootTrackerPlugin); LootTrackerPlugin spyPlugin = Mockito.spy(lootTrackerPlugin);
// Make sure we don't execute addLoot, so we don't have to mock LootTrackerPanel and everything else also // 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); ItemContainer itemContainer = mock(ItemContainer.class);
when(itemContainer.getItems()).thenReturn(new Item[]{ when(itemContainer.getItems()).thenReturn(new Item[]{