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 0624652fb7..67b4cb8467 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 @@ -188,8 +188,8 @@ public class GroundItemsOverlay extends Overlay continue; } - final Color highlighted = plugin.getHighlighted(item.getName(), item.getGePrice(), item.getHaPrice()); - final Color hidden = plugin.getHidden(item.getName(), item.getGePrice(), item.getHaPrice(), item.isTradeable()); + final Color highlighted = plugin.getHighlighted(new NamedQuantity(item), item.getGePrice(), item.getHaPrice()); + final Color hidden = plugin.getHidden(new NamedQuantity(item), item.getGePrice(), item.getHaPrice(), item.isTradeable()); if (highlighted == null && !plugin.isHotKeyPressed()) { 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 cf278ac654..8691cae1d3 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 @@ -61,7 +61,6 @@ import net.runelite.api.Tile; import net.runelite.api.TileItem; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ClientTick; -import net.runelite.client.events.ConfigChanged; import net.runelite.api.events.FocusChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.ItemDespawned; @@ -72,6 +71,7 @@ import net.runelite.api.events.MenuOptionClicked; import net.runelite.client.Notifier; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.events.NpcLootReceived; import net.runelite.client.events.PlayerLootReceived; import net.runelite.client.game.ItemManager; @@ -164,8 +164,8 @@ public class GroundItemsPlugin extends Plugin @Getter private final Map collectedGroundItems = new LinkedHashMap<>(); private final Map priceChecks = new LinkedHashMap<>(); - private LoadingCache highlightedItems; - private LoadingCache hiddenItems; + private LoadingCache highlightedItems; + private LoadingCache hiddenItems; private final Queue droppedItemQueue = EvictingQueue.create(16); // recently dropped items @Provides @@ -233,7 +233,7 @@ public class GroundItemsPlugin extends Plugin } boolean shouldNotify = !config.onlyShowLoot() && config.highlightedColor().equals(getHighlighted( - groundItem.getName(), + new NamedQuantity(groundItem), groundItem.getGePrice(), groundItem.getHaPrice())); @@ -361,7 +361,7 @@ public class GroundItemsPlugin extends Plugin groundItem.setLootType(lootType); boolean shouldNotify = config.onlyShowLoot() && config.highlightedColor().equals(getHighlighted( - groundItem.getName(), + new NamedQuantity(groundItem), groundItem.getGePrice(), groundItem.getHaPrice())); @@ -500,8 +500,8 @@ public class GroundItemsPlugin extends Plugin final int price = itemPrice <= 0 ? itemComposition.getPrice() : itemPrice; final int haPrice = Math.round(itemComposition.getPrice() * Constants.HIGH_ALCHEMY_MULTIPLIER) * quantity; final int gePrice = quantity * price; - final Color hidden = getHidden(itemComposition.getName(), gePrice, haPrice, itemComposition.isTradeable()); - final Color highlighted = getHighlighted(itemComposition.getName(), gePrice, haPrice); + final Color hidden = getHidden(new NamedQuantity(itemComposition.getName(), quantity), gePrice, haPrice, itemComposition.isTradeable()); + final Color highlighted = getHighlighted(new NamedQuantity(itemComposition.getName(), quantity), gePrice, haPrice); final Color color = getItemColor(highlighted, hidden); final boolean canBeRecolored = highlighted != null || (hidden != null && config.recolorMenuHiddenItems()); @@ -569,7 +569,7 @@ public class GroundItemsPlugin extends Plugin config.setHighlightedItem(Text.toCSV(highlightedItemSet)); } - Color getHighlighted(String item, int gePrice, int haPrice) + Color getHighlighted(NamedQuantity item, int gePrice, int haPrice) { if (TRUE.equals(highlightedItems.getUnchecked(item))) { @@ -611,7 +611,7 @@ public class GroundItemsPlugin extends Plugin return null; } - Color getHidden(String item, int gePrice, int haPrice, boolean isTradeable) + Color getHidden(NamedQuantity item, int gePrice, int haPrice, boolean isTradeable) { final boolean isExplicitHidden = TRUE.equals(hiddenItems.getUnchecked(item)); final boolean isExplicitHighlight = TRUE.equals(highlightedItems.getUnchecked(item)); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/ItemThreshold.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/ItemThreshold.java new file mode 100644 index 0000000000..b92522bc1f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/ItemThreshold.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020, dekvall + * 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 java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.Value; + +@Value +class ItemThreshold +{ + enum Inequality + { + LESS_THAN, + MORE_THAN + } + + private static final Pattern QUANTITY_THRESHOLD_PATTERN = Pattern.compile("(.+)(<|>)\\s*(\\d+)"); + + private final String itemName; + private final int quantity; + private final Inequality inequality; + + static ItemThreshold fromConfigEntry(String entry) + { + if (Strings.isNullOrEmpty(entry)) + { + return null; + } + + Matcher matcher = QUANTITY_THRESHOLD_PATTERN.matcher(entry); + + if (matcher.find()) + { + String name = matcher.group(1).trim(); + String sign = matcher.group(2); + int quantity = Integer.parseInt(matcher.group(3)); + Inequality inequality = sign.equals("<") ? Inequality.LESS_THAN : Inequality.MORE_THAN; + + return new ItemThreshold(name, quantity, inequality); + } + + return new ItemThreshold(entry, 0, Inequality.MORE_THAN); + } + + boolean quantityHolds(int itemCount) + { + if (inequality == Inequality.LESS_THAN) + { + return itemCount < quantity; + } + else + { + return itemCount > quantity; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/NamedQuantity.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/NamedQuantity.java new file mode 100644 index 0000000000..1d834089fc --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/NamedQuantity.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020, dekvall + * 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 lombok.RequiredArgsConstructor; +import lombok.Value; + +@Value +@RequiredArgsConstructor +class NamedQuantity +{ + private final String name; + private final int quantity; + + NamedQuantity(GroundItem groundItem) + { + this(groundItem.getName(), groundItem.getQuantity()); + } +} 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 index ff7e94102e..7519bbd351 100644 --- 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 @@ -27,31 +27,37 @@ 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.Objects; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import net.runelite.client.util.WildcardMatcher; -class WildcardMatchLoader extends CacheLoader +class WildcardMatchLoader extends CacheLoader { - private final List nameFilters; + private final List itemThresholds; - WildcardMatchLoader(List nameFilters) + WildcardMatchLoader(List configEntries) { - this.nameFilters = nameFilters; + this.itemThresholds = configEntries.stream() + .map(ItemThreshold::fromConfigEntry) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } @Override - public Boolean load(@Nonnull final String key) + public Boolean load(@Nonnull final NamedQuantity key) { - if (Strings.isNullOrEmpty(key)) + if (Strings.isNullOrEmpty(key.getName())) { return false; } - final String filteredName = key.trim(); + final String filteredName = key.getName().trim(); - for (final String filter : nameFilters) + for (final ItemThreshold entry : itemThresholds) { - if (WildcardMatcher.matches(filter, filteredName)) + if (WildcardMatcher.matches(entry.getItemName(), filteredName) + && entry.quantityHolds(key.getQuantity())) { return true; } 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 index b65dc30076..a7ade4c7d5 100644 --- 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 @@ -32,14 +32,25 @@ import org.junit.Test; public class WildcardMatchLoaderTest { @Test - public void testLoad() + public void testLoadItems() { 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")); + assertTrue(loader.load(new NamedQuantity("rune pouch", 1))); + assertTrue(loader.load(new NamedQuantity("Rune pouch", 1))); + assertFalse(loader.load(new NamedQuantity("Adamant dagger", 1))); + assertTrue(loader.load(new NamedQuantity("Runeite Ore", 1))); + assertTrue(loader.load(new NamedQuantity("Abyssal whip", 1))); + assertFalse(loader.load(new NamedQuantity("Abyssal dagger", 1))); } -} \ No newline at end of file + + @Test + public void testLoadQuantities() + { + WildcardMatchLoader loader = new WildcardMatchLoader(Arrays.asList("rune* < 3", "*whip>3", "nature*<5", "*rune > 30")); + assertTrue(loader.load(new NamedQuantity("Nature Rune", 50))); + assertFalse(loader.load(new NamedQuantity("Nature Impling", 5))); + assertTrue(loader.load(new NamedQuantity("Abyssal whip", 4))); + assertFalse(loader.load(new NamedQuantity("Abyssal dagger", 1))); + assertTrue(loader.load(new NamedQuantity("Rune Longsword", 2))); + } +}