Merge pull request #10912 from dekvall/ground-count

ground items: add support for quantity thresholds
This commit is contained in:
Tomas Slusny
2020-03-17 21:29:51 +01:00
committed by GitHub
6 changed files with 166 additions and 28 deletions

View File

@@ -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())
{

View File

@@ -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<GroundItem.GroundItemKey, GroundItem> collectedGroundItems = new LinkedHashMap<>();
private final Map<Integer, Color> priceChecks = new LinkedHashMap<>();
private LoadingCache<String, Boolean> highlightedItems;
private LoadingCache<String, Boolean> hiddenItems;
private LoadingCache<NamedQuantity, Boolean> highlightedItems;
private LoadingCache<NamedQuantity, Boolean> hiddenItems;
private final Queue<Integer> 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));

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/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;
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/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());
}
}

View File

@@ -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<String, Boolean>
class WildcardMatchLoader extends CacheLoader<NamedQuantity, Boolean>
{
private final List<String> nameFilters;
private final List<ItemThreshold> itemThresholds;
WildcardMatchLoader(List<String> nameFilters)
WildcardMatchLoader(List<String> 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;
}

View File

@@ -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)));
}
}
@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)));
}
}