From 640e0d291549d98d6a69820caed6f288f21cd89e Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 3 Feb 2019 15:18:43 -0500 Subject: [PATCH] mlm plugin: fix ore counter to not count already collected ore --- .../plugins/motherlode/MotherlodePlugin.java | 39 ++-- .../plugins/motherlode/MotherlodeSession.java | 17 +- .../motherlode/MotherlodePluginTest.java | 166 ++++++++++++++++++ 3 files changed, 203 insertions(+), 19 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/motherlode/MotherlodePluginTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodePlugin.java index c72a828a6b..90a5269c1b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodePlugin.java @@ -26,11 +26,15 @@ */ package net.runelite.client.plugins.motherlode; +import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multiset; +import com.google.common.collect.Multisets; import com.google.inject.Provides; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; import javax.inject.Inject; @@ -135,6 +139,7 @@ public class MotherlodePlugin extends Plugin @Inject private MotherlodeSession session; private boolean shouldUpdateOres; + private Multiset inventorySnapshot; @Getter(AccessLevel.PACKAGE) private final Set veins = new HashSet<>(); @@ -193,7 +198,19 @@ public class MotherlodePlugin extends Plugin { int lastSackValue = curSackSize; refreshSackValues(); - shouldUpdateOres = curSackSize != lastSackValue; + shouldUpdateOres = curSackSize < lastSackValue; + if (shouldUpdateOres) + { + // Take a snapshot of the inventory before the new ore is added. + ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY); + if (itemContainer != null) + { + inventorySnapshot = HashMultiset.create(); + Arrays.stream(itemContainer.getItems()) + .filter(item -> MLM_ORE_TYPES.contains(item.getId())) + .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity())); + } + } } } @@ -376,21 +393,23 @@ public class MotherlodePlugin extends Plugin { final ItemContainer container = event.getItemContainer(); - if (!inMlm || container != client.getItemContainer(InventoryID.INVENTORY) || !shouldUpdateOres) + if (!inMlm || !shouldUpdateOres || inventorySnapshot == null || container != client.getItemContainer(InventoryID.INVENTORY)) { return; } - final Item[] inv = container.getItems(); + // Build set of current inventory + Multiset current = HashMultiset.create(); + Arrays.stream(container.getItems()) + .filter(item -> MLM_ORE_TYPES.contains(item.getId())) + .forEach(item -> current.add(item.getId(), item.getQuantity())); - for (Item item : inv) - { - if (MLM_ORE_TYPES.contains(item.getId())) - { - session.updateOreFound(item); - } - } + // Take the difference + Multiset delta = Multisets.difference(current, inventorySnapshot); + // Update the session + delta.forEachEntry(session::updateOreFound); + inventorySnapshot = null; shouldUpdateOres = false; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeSession.java b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeSession.java index cd4407d4b7..e4d00cfda6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeSession.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeSession.java @@ -30,7 +30,6 @@ import javax.inject.Singleton; import lombok.AccessLevel; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Item; import net.runelite.api.ItemID; @Slf4j @@ -107,27 +106,27 @@ public class MotherlodeSession } } - void updateOreFound(Item ore) + void updateOreFound(int item, int count) { - switch (ore.getId()) + switch (item) { case ItemID.GOLDEN_NUGGET: - nuggetsFound += ore.getQuantity(); + nuggetsFound += count; break; case ItemID.COAL: - coalFound++; + coalFound += count; break; case ItemID.GOLD_ORE: - goldFound++; + goldFound += count; break; case ItemID.MITHRIL_ORE: - mithrilFound++; + mithrilFound += count; break; case ItemID.ADAMANTITE_ORE: - adamantiteFound++; + adamantiteFound += count; break; case ItemID.RUNITE_ORE: - runiteFound++; + runiteFound += count; break; default: log.debug("Invalid ore specified. The ore count will not be updated."); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/motherlode/MotherlodePluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/motherlode/MotherlodePluginTest.java new file mode 100644 index 0000000000..9ceaf15247 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/motherlode/MotherlodePluginTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2019, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.motherlode; + +import com.google.inject.Guice; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import java.util.concurrent.ScheduledExecutorService; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; +import net.runelite.api.Varbits; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.events.VarbitChanged; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class MotherlodePluginTest +{ + @Inject + private MotherlodePlugin motherlodePlugin; + + @Mock + @Bind + private Client client; + + @Mock + @Bind + MotherlodeSession motherlodeSession; + + @Mock + @Bind + private MotherlodeConfig motherlodeConfig; + + @Mock + @Bind + private MotherlodeGemOverlay motherlodeGemOverlay; + + @Mock + @Bind + private MotherlodeOreOverlay motherlodeOreOverlay; + + @Mock + @Bind + private MotherlodeRocksOverlay motherlodeRocksOverlay; + + @Mock + @Bind + private MotherlodeSackOverlay motherlodeSackOverlay; + + @Mock + @Bind + private ScheduledExecutorService scheduledExecutorService; + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + + when(client.getGameState()).thenReturn(GameState.LOGGED_IN); + when(client.getMapRegions()).thenReturn(new int[]{14679}); + } + + @Test + public void testOreCounter() + { + // set inMlm + GameStateChanged gameStateChanged = new GameStateChanged(); + gameStateChanged.setGameState(GameState.LOGGED_IN); + motherlodePlugin.onGameStateChanged(gameStateChanged); + + // Initial sack count + when(client.getVar(Varbits.SACK_NUMBER)).thenReturn(42); + motherlodePlugin.onVarbitChanged(new VarbitChanged()); + + // Create before inventory + ItemContainer inventory = mock(ItemContainer.class); + Item[] items = new Item[]{ + mockItem(ItemID.RUNITE_ORE, 1), + mockItem(ItemID.GOLDEN_NUGGET, 4), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.COAL, 1), + + }; + when(inventory.getItems()) + .thenReturn(items); + when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(inventory); + + // Withdraw 20 + when(client.getVar(Varbits.SACK_NUMBER)).thenReturn(22); + motherlodePlugin.onVarbitChanged(new VarbitChanged()); + + inventory = mock(ItemContainer.class); + // +1 rune, +4 nugget, +2 coal, +1 addy + items = new Item[]{ + mockItem(ItemID.RUNITE_ORE, 1), + mockItem(ItemID.RUNITE_ORE, 1), + mockItem(ItemID.GOLDEN_NUGGET, 8), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.COAL, 1), + mockItem(ItemID.ADAMANTITE_ORE, 1), + + }; + when(inventory.getItems()) + .thenReturn(items); + when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(inventory); + + // Trigger comparison + motherlodePlugin.onItemContainerChanged(new ItemContainerChanged(inventory)); + + verify(motherlodeSession).updateOreFound(ItemID.RUNITE_ORE, 1); + verify(motherlodeSession).updateOreFound(ItemID.GOLDEN_NUGGET, 4); + verify(motherlodeSession).updateOreFound(ItemID.COAL, 2); + verify(motherlodeSession).updateOreFound(ItemID.ADAMANTITE_ORE, 1); + verifyNoMoreInteractions(motherlodeSession); + } + + private static Item mockItem(int itemId, int quantity) + { + Item item = mock(Item.class); + when(item.getId()).thenReturn(itemId); + when(item.getQuantity()).thenReturn(quantity); + return item; + } +} \ No newline at end of file