From 82cfa48d9c12a44c4456ab4152d94b1cb1454d34 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 16 Mar 2018 17:02:34 -0400 Subject: [PATCH] ground items: add support for wildcards --- .../grounditems/GroundItemsOverlay.java | 25 ++---- .../grounditems/GroundItemsPlugin.java | 69 ++++++++++++--- .../grounditems/WildcardMatchLoader.java | 85 +++++++++++++++++++ .../grounditems/WildcardMatchLoaderTest.java | 45 ++++++++++ 4 files changed, 196 insertions(+), 28 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/grounditems/WildcardMatchLoader.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/grounditems/WildcardMatchLoaderTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index 9a609bd5e5..312c087f9d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -24,14 +24,13 @@ */ package net.runelite.client.plugins.grounditems; -import static java.lang.Math.max; -import static java.lang.Math.min; import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics2D; +import static java.lang.Math.max; +import static java.lang.Math.min; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -79,12 +78,11 @@ public class GroundItemsOverlay extends Overlay private static final int INSANE_VALUE = 10_000_000; // Used when getting High Alchemy value - multiplied by general store price. private static final float HIGH_ALCHEMY_CONSTANT = 0.6f; - // Regex for splitting the hidden items in the config. - static final String DELIMITER_REGEX = "\\s*,\\s*"; // ItemID for coins private static final int COINS = ItemID.COINS_995; private final Client client; + private final GroundItemsPlugin plugin; private final GroundItemsConfig config; private final StringBuilder itemStringBuilder = new StringBuilder(); @@ -92,24 +90,18 @@ public class GroundItemsOverlay extends Overlay private ItemManager itemManager; @Inject - public GroundItemsOverlay(Client client, GroundItemsConfig config) + public GroundItemsOverlay(Client client, GroundItemsPlugin plugin, GroundItemsConfig config) { setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_SCENE); this.client = client; + this.plugin = plugin; this.config = config; } @Override public Dimension render(Graphics2D graphics, java.awt.Point parent) { - // gets the hidden/highlighted items from the text box in the config - String configItems = config.getHiddenItems().toLowerCase(); - List hiddenItems = Arrays.asList(configItems.split(DELIMITER_REGEX)); - // note: both of these lists are immutable - configItems = config.getHighlightItems().toLowerCase(); - List highlightedItems = Arrays.asList(configItems.split(DELIMITER_REGEX)); - Region region = client.getRegion(); Tile[][][] tiles = region.getTiles(); FontMetrics fm = graphics.getFontMetrics(); @@ -159,8 +151,7 @@ public class GroundItemsOverlay extends Overlay Integer currentQuantity = items.get(itemId); - String itemName = itemDefinition.getName().toLowerCase(); - if (config.showHighlightedOnly() ? highlightedItems.contains(itemName) : !hiddenItems.contains(itemName)) + if (config.showHighlightedOnly() ? plugin.isHighlighted(itemDefinition.getName()) : !plugin.isHidden(itemDefinition.getName())) { if (itemDefinition.getNote() != -1) { @@ -185,7 +176,7 @@ public class GroundItemsOverlay extends Overlay gePrice = itemPrice == null ? 0 : itemPrice.getPrice() * quantity; alchPrice = Math.round(itemDefinition.getPrice() * HIGH_ALCHEMY_CONSTANT) * quantity; } - if (highlightedItems.contains(itemDefinition.getName().toLowerCase()) || + if (plugin.isHighlighted(itemDefinition.getName()) || gePrice == 0 || ((gePrice >= config.getHideUnderGeValue()) && (alchPrice >= config.getHideUnderHAValue()))) { @@ -257,7 +248,7 @@ public class GroundItemsOverlay extends Overlay .append(" gp)"); } - if (highlightedItems.contains(item.getName().toLowerCase())) + if (plugin.isHighlighted(item.getName())) { textColor = config.highlightedColor(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java index 17a85e370b..9f78b6d623 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java @@ -24,11 +24,16 @@ */ package net.runelite.client.plugins.grounditems; +import com.google.common.base.Splitter; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; import com.google.common.eventbus.Subscribe; import com.google.inject.Provides; import java.awt.Color; -import java.util.Arrays; +import static java.lang.Boolean.TRUE; import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.Item; @@ -39,6 +44,7 @@ import net.runelite.api.MenuEntry; import net.runelite.api.Node; import net.runelite.api.Region; import net.runelite.api.Tile; +import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.MenuEntryAdded; import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; @@ -67,6 +73,9 @@ public class GroundItemsPlugin extends Plugin @Inject private GroundItemsOverlay overlay; + private LoadingCache highlightedItems; + private LoadingCache hiddenItems; + @Provides GroundItemsConfig provideConfig(ConfigManager configManager) { @@ -79,6 +88,42 @@ public class GroundItemsPlugin extends Plugin return overlay; } + @Override + protected void startUp() + { + reset(); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("grounditems")) + { + reset(); + } + } + + private void reset() + { + Splitter COMMA_SPLITTER = Splitter.on(Pattern.compile("\\s*,\\s*")); + + // gets the hidden items from the text box in the config + List hiddenItemList = COMMA_SPLITTER.splitToList(config.getHiddenItems().trim()); + + // gets the highlighted items from the text box in the config + List highlightedItemsList = COMMA_SPLITTER.splitToList(config.getHighlightItems().trim()); + + highlightedItems = CacheBuilder.newBuilder() + .maximumSize(512L) + .expireAfterAccess(10, TimeUnit.MINUTES) + .build(new WildcardMatchLoader(highlightedItemsList)); + + hiddenItems = CacheBuilder.newBuilder() + .maximumSize(512L) + .expireAfterAccess(10, TimeUnit.MINUTES) + .build(new WildcardMatchLoader(hiddenItemList)); + } + private ItemPrice getItemPrice(ItemComposition itemComposition) { if (itemComposition.getNote() != -1) @@ -95,19 +140,12 @@ public class GroundItemsPlugin extends Plugin public void onMenuEntryAdded(MenuEntryAdded event) { if ((config.highlightMenuOption() || config.highlightMenuItemName()) && event.getOption().equals("Take") - && event.getType() == MenuAction.GROUND_ITEM_THIRD_OPTION.getId()) + && event.getType() == MenuAction.GROUND_ITEM_THIRD_OPTION.getId()) { - String hiddenItemsStr = config.getHiddenItems().toLowerCase(); - List hiddenItems = Arrays.asList(hiddenItemsStr.split(GroundItemsOverlay.DELIMITER_REGEX)); - - String highlightItemsStr = config.getHighlightItems().toLowerCase(); - List highlightedItems = Arrays.asList(highlightItemsStr.split(GroundItemsOverlay.DELIMITER_REGEX)); - int itemId = event.getIdentifier(); ItemComposition itemComposition = client.getItemDefinition(itemId); - String name = itemComposition.getName().toLowerCase(); - if (hiddenItems.contains(name)) + if (isHidden(itemComposition.getName())) { return; } @@ -146,7 +184,7 @@ public class GroundItemsPlugin extends Plugin color = overlay.getCostColor(cost); } - if (highlightedItems.contains(name)) + if (isHighlighted(itemComposition.getName())) { color = config.highlightedColor(); } @@ -175,4 +213,13 @@ public class GroundItemsPlugin extends Plugin } } + public boolean isHighlighted(String item) + { + return TRUE.equals(highlightedItems.getUnchecked(item)); + } + + public boolean isHidden(String item) + { + return TRUE.equals(hiddenItems.getUnchecked(item)); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/WildcardMatchLoader.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/WildcardMatchLoader.java new file mode 100644 index 0000000000..ab6da416bd --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/WildcardMatchLoader.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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.grounditems; + +import com.google.common.base.Strings; +import com.google.common.cache.CacheLoader; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.annotation.Nonnull; + +class WildcardMatchLoader extends CacheLoader +{ + // Regex used for matching item names with others + private static final Pattern WILDCARD_PATTERN = Pattern.compile("(?i)[^*]+|(\\*)"); + + private final List nameFilters; + + WildcardMatchLoader(List nameFilters) + { + this.nameFilters = nameFilters; + } + + @Override + public Boolean load(@Nonnull final String key) + { + if (Strings.isNullOrEmpty(key)) + { + return false; + } + + final String filteredName = key.trim(); + + for (final String filter : nameFilters) + { + final Matcher matcher = WILDCARD_PATTERN.matcher(filter); + final StringBuffer buffer = new StringBuffer(); + + buffer.append("(?i)"); + while (matcher.find()) + { + if (matcher.group(1) != null) + { + matcher.appendReplacement(buffer, ".*"); + } + else + { + matcher.appendReplacement(buffer, "\\\\Q" + matcher.group(0) + "\\\\E"); + } + } + + matcher.appendTail(buffer); + final String replaced = buffer.toString(); + + if (filteredName.matches(replaced)) + { + return true; + } + } + + return false; + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/WildcardMatchLoaderTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/WildcardMatchLoaderTest.java new file mode 100644 index 0000000000..b65dc30076 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/WildcardMatchLoaderTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018, 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.grounditems; + +import java.util.Arrays; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class WildcardMatchLoaderTest +{ + @Test + public void testLoad() + { + WildcardMatchLoader loader = new WildcardMatchLoader(Arrays.asList("rune*", "Abyssal whip")); + assertTrue(loader.load("rune pouch")); + assertTrue(loader.load("Rune pouch")); + assertFalse(loader.load("Adamant dagger")); + assertTrue(loader.load("Runeite Ore")); + assertTrue(loader.load("Abyssal whip")); + assertFalse(loader.load("Abyssal dagger")); + } +} \ No newline at end of file