From c4afc599ed965c49dc96487916af62c71cde2dac Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 20 Jan 2019 16:05:17 -0500 Subject: [PATCH] examine plugin: drop examines for tradable items and large stacks --- .../client/plugins/examine/ExaminePlugin.java | 25 +++- .../plugins/examine/ExaminePluginTest.java | 120 ++++++++++++++++++ 2 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/examine/ExaminePluginTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java index 8cd88fdbb3..2b4a623837 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java @@ -30,6 +30,7 @@ import java.time.Instant; import java.util.ArrayDeque; import java.util.Deque; import java.util.concurrent.ScheduledExecutorService; +import java.util.regex.Pattern; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; @@ -68,13 +69,16 @@ import net.runelite.http.api.examine.ExamineClient; public class ExaminePlugin extends Plugin { private static final float HIGH_ALCHEMY_CONSTANT = 0.6f; + private static final Pattern X_PATTERN = Pattern.compile("^\\d+ x "); - private final ExamineClient examineClient = new ExamineClient(); private final Deque pending = new ArrayDeque<>(); private final Cache cache = CacheBuilder.newBuilder() .maximumSize(128L) .build(); + @Inject + private ExamineClient examineClient; + @Inject private Client client; @@ -192,11 +196,12 @@ public class ExaminePlugin extends Plugin log.debug("Got examine for {} {}: {}", pendingExamine.getType(), pendingExamine.getId(), event.getMessage()); // If it is an item, show the price of it + final ItemComposition itemComposition; if (pendingExamine.getType() == ExamineType.ITEM || pendingExamine.getType() == ExamineType.ITEM_BANK_EQ) { final int itemId = pendingExamine.getId(); final int itemQuantity = pendingExamine.getQuantity(); - final ItemComposition itemComposition = itemManager.getItemComposition(itemId); + itemComposition = itemManager.getItemComposition(itemId); if (itemComposition != null) { @@ -204,6 +209,22 @@ public class ExaminePlugin extends Plugin executor.submit(() -> getItemPrice(id, itemComposition, itemQuantity)); } } + else + { + itemComposition = null; + } + + // Don't submit examine info for tradeable items, which we already have from the RS item api + if (itemComposition != null && itemComposition.isTradeable()) + { + return; + } + + // Large quantities of items show eg. 100000 x Coins + if (type == ExamineType.ITEM && X_PATTERN.matcher(event.getMessage()).lookingAt()) + { + return; + } CacheKey key = new CacheKey(type, pendingExamine.getId()); Boolean cached = cache.getIfPresent(key); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/examine/ExaminePluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/examine/ExaminePluginTest.java new file mode 100644 index 0000000000..7c00bab4a9 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/examine/ExaminePluginTest.java @@ -0,0 +1,120 @@ +/* + * 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.examine; + +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.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.ItemID; +import net.runelite.api.MenuAction; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.widgets.Widget; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.game.ItemManager; +import net.runelite.http.api.examine.ExamineClient; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import org.mockito.Mock; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class ExaminePluginTest +{ + @Inject + ExaminePlugin examinePlugin; + + @Mock + @Bind + ExamineClient examineClient; + + @Mock + @Bind + Client client; + + @Mock + @Bind + ChatMessageManager chatMessageManager; + + @Mock + @Bind + ItemManager itemManager; + + @Mock + @Bind + ScheduledExecutorService scheduledExecutorService; + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + } + + @Test + public void testItem() + { + when(client.getWidget(anyInt(), anyInt())).thenReturn(mock(Widget.class)); + + MenuOptionClicked menuOptionClicked = new MenuOptionClicked(); + menuOptionClicked.setMenuOption("Examine"); + menuOptionClicked.setMenuAction(MenuAction.EXAMINE_ITEM); + menuOptionClicked.setId(ItemID.ABYSSAL_WHIP); + examinePlugin.onMenuOptionClicked(menuOptionClicked); + + ChatMessage chatMessage = new ChatMessage(ChatMessageType.EXAMINE_ITEM, "", "A weapon from the abyss.", ""); + examinePlugin.onChatMessage(chatMessage); + + // This passes due to not mocking the ItemComposition for the whip + verify(examineClient).submitItem(anyInt(), anyString()); + } + + @Test + public void testLargeStacks() + { + when(client.getWidget(anyInt(), anyInt())).thenReturn(mock(Widget.class)); + + MenuOptionClicked menuOptionClicked = new MenuOptionClicked(); + menuOptionClicked.setMenuOption("Examine"); + menuOptionClicked.setMenuAction(MenuAction.EXAMINE_ITEM); + menuOptionClicked.setId(ItemID.ABYSSAL_WHIP); + examinePlugin.onMenuOptionClicked(menuOptionClicked); + + ChatMessage chatMessage = new ChatMessage(ChatMessageType.EXAMINE_ITEM, "", "100000 x Abyssal whip", ""); + examinePlugin.onChatMessage(chatMessage); + + verify(examineClient, never()).submitItem(anyInt(), anyString()); + } +} \ No newline at end of file