Skip to content

Commit 203ad02

Browse files
committed
fix(loottracker): Track automated bird nest searching (runelite#19975)
- Added support for tracking the loot received from the next searched bird nest that's automated by the game itself - Modified LootTrackerPlugin#onItemContainerChanged to see if a bird nest was searched by the game and whether or not to keep processing inventory changes while there are searchable bird nests remaining - Added new test case LootTrackerPluginTest#testBirdNests
1 parent 636a5dc commit 203ad02

2 files changed

Lines changed: 78 additions & 2 deletions

File tree

runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1221,12 +1221,27 @@ public void onItemContainerChanged(ItemContainerChanged event)
12211221

12221222
log.debug("Inv change: {} Ground items: {}", items, groundItems);
12231223

1224+
final Set<Integer> removedItemIDs = diffr.entrySet().stream().map(Multiset.Entry::getElement).collect(Collectors.toSet());
1225+
final Set<Integer> currentInventoryItemIDs = currentInventory.entrySet().stream().map(Multiset.Entry::getElement).collect(Collectors.toSet());
1226+
// Determines whether to ignore #resetEvent or not due to the game possibly continuing to modify the players inventory without any interaction
1227+
// An example of this would be searching bird nests, as after searching one nest, the game will continue to search the rest of the nests in the inventory until interrupted
1228+
boolean ignoreReset = false;
1229+
if (removedItemIDs.stream().anyMatch(BIRDNEST_IDS::contains)) {
1230+
onInvChange(collectInvItems(LootRecordType.EVENT, BIRDNEST_EVENT));
1231+
if (currentInventoryItemIDs.stream().anyMatch(BIRDNEST_IDS::contains)) {
1232+
ignoreReset = true;
1233+
}
1234+
}
1235+
12241236
if (inventorySnapshotCb != null)
12251237
{
12261238
inventorySnapshotCb.accept(items, groundItems, diffr);
12271239
}
12281240

1229-
resetEvent();
1241+
if (!ignoreReset)
1242+
{
1243+
resetEvent();
1244+
}
12301245
}
12311246

12321247
@Subscribe

runelite-client/src/test/java/net/runelite/client/plugins/loottracker/LootTrackerPluginTest.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import net.runelite.api.ItemComposition;
4444
import net.runelite.api.ItemContainer;
4545
import net.runelite.api.IterableHashTable;
46+
import net.runelite.api.MenuAction;
4647
import net.runelite.api.MessageNode;
4748
import net.runelite.api.Player;
4849
import net.runelite.api.Skill;
@@ -52,6 +53,7 @@
5253
import net.runelite.api.events.ChatMessage;
5354
import net.runelite.api.events.GameStateChanged;
5455
import net.runelite.api.events.ItemContainerChanged;
56+
import net.runelite.api.events.MenuOptionClicked;
5557
import net.runelite.api.events.WidgetLoaded;
5658
import net.runelite.api.gameval.InterfaceID;
5759
import net.runelite.api.gameval.InventoryID;
@@ -583,7 +585,7 @@ public void testWintertodtRewardCart()
583585
when(client.getLocalPlayer()).thenReturn(player);
584586
when(client.getBoostedSkillLevel(Skill.FIREMAKING)).thenReturn(99);
585587

586-
doNothing().when(lootTrackerPlugin).addLoot(any(), anyInt(), any(), any(), anyCollection());
588+
doNothing().when(lootTrackerPlugin).addLoot(any(), anyInt(), any(), any(), any(Collection.class));
587589

588590
ItemContainer itemContainer = mock(ItemContainer.class);
589591
when(itemContainer.getItems()).thenReturn(new Item[]{
@@ -686,4 +688,63 @@ public void testLargeSalvage()
686688

687689
verify(lootTrackerPlugin).addLoot("Large salvage", -1, LootRecordType.EVENT, null, Collections.singletonList(new ItemStack(ItemID.NAILS, 4)));
688690
}
691+
692+
@Test
693+
public void testBirdNests() {
694+
List<ItemStack> initialItems = Collections.singletonList(
695+
new ItemStack(ItemID.BIRD_NEST_SEEDS_JAN2019, 2)
696+
);
697+
sendInvChange(InventoryID.INV, initialItems);
698+
699+
MenuOptionClicked searchBirdNest = mock(MenuOptionClicked.class);
700+
when(searchBirdNest.getMenuAction()).thenReturn(MenuAction.CC_OP);
701+
when(searchBirdNest.isItemOp()).thenReturn(true);
702+
when(searchBirdNest.getMenuOption()).thenReturn("Search");
703+
when(searchBirdNest.getItemId()).thenReturn(ItemID.BIRD_NEST_SEEDS_JAN2019);
704+
lootTrackerPlugin.onMenuOptionClicked(searchBirdNest);
705+
706+
List<ItemStack> itemsAfterOneSearch = Arrays.asList(
707+
new ItemStack(ItemID.BIRD_NEST_EMPTY, 1),
708+
new ItemStack(ItemID.BIRD_NEST_SEEDS_JAN2019, 1),
709+
new ItemStack(ItemID.ACORN, 1)
710+
);
711+
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You take an acorn out of the bird's nest.", "", 0);
712+
lootTrackerPlugin.onChatMessage(chatMessage);
713+
sendInvChange(InventoryID.INV, itemsAfterOneSearch);
714+
verify(lootTrackerPlugin).addLoot("Bird nest", -1, LootRecordType.EVENT, null, Arrays.asList(
715+
new ItemStack(ItemID.ACORN, 1),
716+
new ItemStack(ItemID.BIRD_NEST_EMPTY, 1)
717+
));
718+
719+
lootTrackerPlugin.onMenuOptionClicked(searchBirdNest);
720+
721+
List<ItemStack> itemsAfterTwoSearches = Arrays.asList(
722+
new ItemStack(ItemID.BIRD_NEST_EMPTY, 2),
723+
new ItemStack(ItemID.ACORN, 1),
724+
new ItemStack(ItemID.CELASTRUS_TREE_SEED, 1)
725+
);
726+
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You take a celastrus tree seed out of the bird's nest.", "", 0);
727+
lootTrackerPlugin.onChatMessage(chatMessage);
728+
sendInvChange(InventoryID.INV, itemsAfterTwoSearches);
729+
verify(lootTrackerPlugin).addLoot("Bird nest", -1, LootRecordType.EVENT, null, Arrays.asList(
730+
new ItemStack(ItemID.BIRD_NEST_EMPTY, 1),
731+
new ItemStack(ItemID.CELASTRUS_TREE_SEED, 1)
732+
));
733+
734+
// Additional test to make sure ignoring reset didn't break anything
735+
List<ItemStack> itemsPostBirdNestTest = Arrays.asList(
736+
new ItemStack(ItemID.SAILING_LARGE_SHIPWRECK_SALVAGE, 1)
737+
);
738+
739+
sendInvChange(InventoryID.INV, itemsPostBirdNestTest);
740+
741+
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You sort through the large salvage and find: 4 x Steel nails.", "", 0);
742+
lootTrackerPlugin.onChatMessage(chatMessage);
743+
744+
sendInvChange(InventoryID.INV, Collections.singletonList(
745+
new ItemStack(ItemID.NAILS, 4)
746+
));
747+
748+
verify(lootTrackerPlugin).addLoot("Large salvage", -1, LootRecordType.EVENT, null, Collections.singletonList(new ItemStack(ItemID.NAILS, 4)));
749+
}
689750
}

0 commit comments

Comments
 (0)