Merge pull request #1114 from deathbeam/ground-items-improvements

Improve ground items plugin
This commit is contained in:
Adam
2018-03-30 21:45:11 -04:00
committed by GitHub
5 changed files with 404 additions and 241 deletions

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* 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.api.events;
import lombok.Value;
import net.runelite.api.Tile;
@Value
public class ItemLayerChanged
{
private Tile tile;
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* 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.Builder;
import lombok.Data;
import lombok.Value;
import net.runelite.api.coords.WorldPoint;
@Data
@Builder
class GroundItem
{
private int id;
private int itemId;
private String name;
private int quantity;
private WorldPoint location;
private int haPrice;
private int gePrice;
@Value
static class GroundItemKey
{
private int itemId;
private WorldPoint location;
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Aria <aria@ar1as.space>
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,72 +30,50 @@ import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import static java.lang.Math.max;
import static java.lang.Math.min;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Item;
import net.runelite.api.ItemComposition;
import net.runelite.api.ItemID;
import net.runelite.api.ItemLayer;
import net.runelite.api.Node;
import net.runelite.api.Perspective;
import net.runelite.api.Player;
import net.runelite.api.Point;
import net.runelite.api.Region;
import net.runelite.api.Tile;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.game.ItemManager;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.TextComponent;
import net.runelite.client.util.StackFormatter;
import net.runelite.http.api.item.ItemPrice;
public class GroundItemsOverlay extends Overlay
{
private static final int REGION_SIZE = 104;
private static final int MAX_DISTANCE = 2500;
// We must offset the text on the z-axis such that
// it doesn't obscure the ground items below it.
private static final int OFFSET_Z = 20;
// The game won't send anything higher than this value to the plugin -
// so we replace any item quantity higher with "Lots" instead.
private static final int MAX_QUANTITY = 65535;
// The max distance in tiles between the player and the item.
private static final int MAX_RANGE = 18;
// The 15 pixel gap between each drawn ground item.
private static final int STRING_GAP = 15;
// Threshold for highlighting items as blue.
static final int LOW_VALUE = 20_000;
private static final int LOW_VALUE = 20_000;
// Threshold for highlighting items as green.
private static final int MEDIUM_VALUE = 100_000;
// Threshold for highlighting items as amber.
private static final int HIGH_VALUE = 1_000_000;
// Threshold for highlighting items as pink.
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;
// ItemID for coins
private static final int COINS = ItemID.COINS_995;
// Size of the hidden/highlight boxes
private static final int RECTANGLE_SIZE = 8;
private Rectangle itemHiddenBox;
private Rectangle itemHighlightBox;
private final Client client;
private final GroundItemsPlugin plugin;
private final GroundItemsConfig config;
private final StringBuilder itemStringBuilder = new StringBuilder();
@Inject
private ItemManager itemManager;
private final TextComponent textComponent = new TextComponent();
private final Map<WorldPoint, Integer> offsetMap = new HashMap<>();
@Inject
public GroundItemsOverlay(Client client, GroundItemsPlugin plugin, GroundItemsConfig config)
@@ -109,239 +88,164 @@ public class GroundItemsOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
Region region = client.getRegion();
Tile[][][] tiles = region.getTiles();
FontMetrics fm = graphics.getFontMetrics();
final FontMetrics fm = graphics.getFontMetrics();
final Player player = client.getLocalPlayer();
Player player = client.getLocalPlayer();
if (player == null || client.getViewportWidget() == null)
{
return null;
}
plugin.checkItems();
graphics.setFont(FontManager.getRunescapeSmallFont());
offsetMap.clear();
final LocalPoint localLocation = player.getLocalLocation();
int z = client.getPlane();
LocalPoint from = player.getLocalLocation();
int lowerX = max(0, from.getRegionX() - MAX_RANGE);
int lowerY = max(0, from.getRegionY() - MAX_RANGE);
int upperX = min(from.getRegionX() + MAX_RANGE, REGION_SIZE - 1);
int upperY = min(from.getRegionY() + MAX_RANGE, REGION_SIZE - 1);
// Clear boxes
if (plugin.isHotKeyPressed())
for (GroundItem item : plugin.getCollectedGroundItems().values())
{
plugin.getHiddenBoxes().clear();
plugin.getHighlightBoxes().clear();
}
final LocalPoint groundPoint = LocalPoint.fromWorld(client, item.getLocation());
for (int x = lowerX; x <= upperX; ++x)
{
for (int y = lowerY; y <= upperY; ++y)
if (groundPoint == null || localLocation.distanceTo(groundPoint) > MAX_DISTANCE)
{
Tile tile = tiles[z][x][y];
if (tile == null)
continue;
}
final boolean highlighted = plugin.isHighlighted(item.getName());
if (!plugin.isHotKeyPressed() && !highlighted
&& ((item.getGePrice() > 0 && item.getGePrice() < config.getHideUnderGeValue())
|| item.getHaPrice() < config.getHideUnderHAValue()))
{
continue;
}
final boolean hidden = plugin.isHidden(item.getName());
final Color color = getCostColor(item.getGePrice() > 0 ? item.getGePrice() : item.getHaPrice(),
highlighted, hidden);
itemStringBuilder.append(item.getName());
if (item.getQuantity() > 1)
{
if (item.getQuantity() >= MAX_QUANTITY)
{
continue;
itemStringBuilder.append(" (Lots!)");
}
ItemLayer itemLayer = tile.getItemLayer();
if (itemLayer == null)
else
{
continue;
itemStringBuilder.append(" (").append(item.getQuantity()).append(")");
}
}
Node current = itemLayer.getBottom();
Map<Integer, Integer> items = new LinkedHashMap<>();
// adds the items on the ground to the ArrayList to be drawn
while (current instanceof Item)
{
Item item = (Item) current;
int itemId = item.getId();
int itemQuantity = item.getQuantity();
ItemComposition itemDefinition = itemManager.getItemComposition(itemId);
if (config.showGEPrice() && item.getGePrice() > 0)
{
itemStringBuilder.append(" (EX: ")
.append(StackFormatter.quantityToStackSize(item.getGePrice()))
.append(" gp)");
}
Integer currentQuantity = items.get(itemId);
if (config.showHAValue() && item.getHaPrice() > 0)
{
itemStringBuilder.append(" (HA: ")
.append(StackFormatter.quantityToStackSize(item.getHaPrice()))
.append(" gp)");
}
if ((config.showHighlightedOnly() ? plugin.isHighlighted(itemDefinition.getName()) : !plugin.isHidden(itemDefinition.getName())) || plugin.isHotKeyPressed())
{
if (itemDefinition.getNote() != -1)
{
itemId = itemDefinition.getLinkedNoteId();
}
final String itemString = itemStringBuilder.toString();
itemStringBuilder.setLength(0);
int quantity = currentQuantity == null
? itemQuantity
: currentQuantity + itemQuantity;
final Point textPoint = Perspective.getCanvasTextLocation(client,
graphics,
groundPoint,
itemString, OFFSET_Z);
ItemPrice itemPrice = itemManager.getItemPriceAsync(itemId);
if (textPoint == null)
{
continue;
}
int gePrice, alchPrice;
final int offset = offsetMap.compute(item.getLocation(), (k, v) -> v != null ? v + 1 : 0);
final int textX = textPoint.getX();
final int textY = textPoint.getY() - (STRING_GAP * offset);
if (itemId == COINS)
{
gePrice = quantity;
alchPrice = quantity;
}
else
{
gePrice = itemPrice == null ? 0 : itemPrice.getPrice() * quantity;
alchPrice = Math.round(itemDefinition.getPrice() * HIGH_ALCHEMY_CONSTANT) * quantity;
}
if (plugin.isHighlighted(itemDefinition.getName()) ||
gePrice == 0 || ((gePrice >= config.getHideUnderGeValue()) &&
(alchPrice >= config.getHideUnderHAValue())))
{
items.put(itemId, quantity);
}
}
textComponent.setText(itemString);
textComponent.setColor(color);
textComponent.setPosition(new java.awt.Point(textX, textY));
textComponent.render(graphics);
current = current.getNext();
}
if (plugin.isHotKeyPressed())
{
final int stringWidth = fm.stringWidth(itemString);
final int stringHeight = fm.getHeight();
final int descent = fm.getDescent();
// The bottom item is drawn first
List<Integer> itemIds = new ArrayList<>(items.keySet());
Collections.reverse(itemIds);
// Hidden box
final Rectangle itemHiddenBox = new Rectangle(
textX + stringWidth,
textY - (stringHeight / 2) - descent,
RECTANGLE_SIZE,
stringHeight / 2);
for (int i = 0; i < itemIds.size(); ++i)
{
Point point = itemLayer.getCanvasLocation(itemLayer.getHeight() + OFFSET_Z);
// if the item is offscreen, don't bother drawing it
if (point == null)
{
continue;
}
plugin.getHiddenBoxes().put(itemHiddenBox, item.getName());
int itemId = itemIds.get(i);
int quantity = items.get(itemId);
ItemComposition item = itemManager.getItemComposition(itemId);
// Highlight box
final Rectangle itemHighlightBox = new Rectangle(
textX + stringWidth + RECTANGLE_SIZE + 2,
textY - (stringHeight / 2) - descent,
RECTANGLE_SIZE,
stringHeight / 2);
if (item == null)
{
continue;
}
plugin.getHighlightBoxes().put(itemHighlightBox, item.getName());
itemStringBuilder.append(item.getName());
if (quantity > 1)
{
if (quantity >= MAX_QUANTITY)
{
itemStringBuilder.append(" (Lots!)");
}
else
{
itemStringBuilder.append(" (").append(quantity).append(")");
}
}
final Point mousePos = client.getMouseCanvasPosition();
boolean mouseInHiddenBox = itemHiddenBox.contains(mousePos.getX(), mousePos.getY());
boolean mouseInHighlightBox = itemHighlightBox.contains(mousePos.getX(), mousePos.getY());
// sets item ID to unnoted version, if noted
if (item.getNote() != -1)
{
itemId = item.getLinkedNoteId();
}
// Draw hidden box
drawRectangle(graphics, itemHiddenBox, mouseInHiddenBox ? Color.RED : color, hidden, true);
Color textColor = config.defaultColor(); // Color to use when drawing the ground item
ItemPrice itemPrice = itemManager.getItemPriceAsync(itemId);
if (itemPrice != null && config.showGEPrice())
{
int cost = itemPrice.getPrice() * quantity;
textColor = getCostColor(cost);
itemStringBuilder.append(" (EX: ")
.append(StackFormatter.quantityToStackSize(cost))
.append(" gp)");
}
if (config.showHAValue())
{
itemStringBuilder.append(" (HA: ")
.append(Math.round(item.getPrice() * HIGH_ALCHEMY_CONSTANT) * quantity)
.append(" gp)");
}
if (plugin.isHighlighted(item.getName()))
{
textColor = config.highlightedColor();
}
String itemString = itemStringBuilder.toString();
itemStringBuilder.setLength(0);
int screenX = point.getX() + 2 - (fm.stringWidth(itemString) / 2);
int screenY = point.getY() - (STRING_GAP * i);
// Drawing the shadow for the text, 1px on both x and y
graphics.setColor(Color.BLACK);
graphics.drawString(itemString, screenX + 1, screenY + 1);
// Drawing the text itself
graphics.setColor(textColor);
graphics.drawString(itemString, screenX, screenY);
if (plugin.isHotKeyPressed())
{
// Hidden box
itemHiddenBox = new Rectangle
(
screenX + fm.stringWidth(itemString),
screenY - (fm.getHeight() / 2) - fm.getDescent(),
RECTANGLE_SIZE,
fm.getHeight() / 2
);
plugin.getHiddenBoxes().put(itemHiddenBox, item.getName());
// Highlight box
itemHighlightBox = new Rectangle
(
screenX + fm.stringWidth(itemString) + RECTANGLE_SIZE + 2,
screenY - (fm.getHeight() / 2) - fm.getDescent(),
RECTANGLE_SIZE,
fm.getHeight() / 2
);
plugin.getHighlightBoxes().put(itemHighlightBox, item.getName());
Point mousePos = client.getMouseCanvasPosition();
boolean mouseInHiddenBox = itemHiddenBox.contains(mousePos.getX(), mousePos.getY());
boolean mouseInHighlightBox = itemHighlightBox.contains(mousePos.getX(), mousePos.getY());
// Draw hidden box
drawRectangle(graphics, itemHiddenBox, mouseInHiddenBox ? Color.RED : textColor, plugin.isHidden(item.getName()), true);
// Draw highlight box
drawRectangle(graphics, itemHighlightBox, mouseInHighlightBox ? Color.GREEN : textColor, plugin.isHighlighted(item.getName()), false);
}
}
// Draw highlight box
drawRectangle(graphics, itemHighlightBox, mouseInHighlightBox ? Color.GREEN : color, highlighted, false);
}
}
return null;
}
Color getCostColor(int cost)
Color getCostColor(int cost, boolean highlighted, boolean hidden)
{
if (hidden)
{
return Color.GRAY;
}
if (highlighted)
{
return config.highlightedColor();
}
// set the color according to rarity, if possible
if (cost >= INSANE_VALUE) // 10,000,000 gp
{
return config.insaneValueColor();
}
else if (cost >= HIGH_VALUE) // 1,000,000 gp
if (cost >= HIGH_VALUE) // 1,000,000 gp
{
return config.highValueColor();
}
else if (cost >= MEDIUM_VALUE) // 100,000 gp
if (cost >= MEDIUM_VALUE) // 100,000 gp
{
return config.mediumValueColor();
}
else if (cost >= LOW_VALUE) // 20,000 gp
if (cost >= LOW_VALUE) // 20,000 gp
{
return config.lowValueColor();
}
else
{
return config.defaultColor();
}
return config.defaultColor();
}
private void drawRectangle(Graphics2D graphics, Rectangle rect, Color color, boolean inList, boolean hiddenBox)
@@ -360,23 +264,23 @@ public class GroundItemsOverlay extends Overlay
graphics.setColor(Color.WHITE);
// Minus symbol
graphics.drawLine
(
rect.x + 2,
rect.y + (RECTANGLE_SIZE / 2),
rect.x + RECTANGLE_SIZE - 2,
rect.y + (RECTANGLE_SIZE / 2)
);
(
rect.x + 2,
rect.y + (RECTANGLE_SIZE / 2),
rect.x + RECTANGLE_SIZE - 2,
rect.y + (RECTANGLE_SIZE / 2)
);
if (!hiddenBox)
{
// Plus symbol
graphics.drawLine
(
rect.x + (RECTANGLE_SIZE / 2),
rect.y + 2,
rect.x + (RECTANGLE_SIZE / 2),
rect.y + RECTANGLE_SIZE - 2
);
(
rect.x + (RECTANGLE_SIZE / 2),
rect.y + 2,
rect.x + (RECTANGLE_SIZE / 2),
rect.y + RECTANGLE_SIZE - 2
);
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Aria <aria@ar1as.space>
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,6 +29,7 @@ import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Provides;
import java.awt.Color;
@@ -35,25 +37,37 @@ import java.awt.Rectangle;
import static java.lang.Boolean.TRUE;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.Item;
import net.runelite.api.ItemComposition;
import net.runelite.api.ItemID;
import net.runelite.api.ItemLayer;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.Node;
import net.runelite.api.Player;
import net.runelite.api.Region;
import net.runelite.api.Tile;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.FocusChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ItemLayerChanged;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.game.ItemManager;
@@ -67,8 +81,18 @@ import net.runelite.http.api.item.ItemPrice;
@PluginDescriptor(
name = "Ground Items"
)
@Slf4j
public class GroundItemsPlugin extends Plugin
{
//Size of one region
private static final int REGION_SIZE = 104;
// The max distance in tiles between the player and the item.
private static final int MAX_RANGE = 18;
// Used when getting High Alchemy value - multiplied by general store price.
private static final float HIGH_ALCHEMY_CONSTANT = 0.6f;
// ItemID for coins
private static final int COINS = ItemID.COINS_995;
@Getter(AccessLevel.PACKAGE)
private final Map<Rectangle, String> hiddenBoxes = new HashMap<>();
@@ -81,6 +105,7 @@ public class GroundItemsPlugin extends Plugin
private List<String> hiddenItemList = new ArrayList<>();
private List<String> highlightedItemsList = new ArrayList<>();
private boolean dirty;
@Inject
private GroundItemInputListener inputListener;
@@ -94,9 +119,6 @@ public class GroundItemsPlugin extends Plugin
@Inject
private Client client;
@Inject
private ConfigManager configManager;
@Inject
private ItemManager itemManager;
@@ -106,9 +128,24 @@ public class GroundItemsPlugin extends Plugin
@Inject
private GroundItemsOverlay overlay;
@Getter
private final Map<GroundItem.GroundItemKey, GroundItem> collectedGroundItems = new LinkedHashMap<>();
private final List<GroundItem> groundItems = new ArrayList<>();
private LoadingCache<String, Boolean> highlightedItems;
private LoadingCache<String, Boolean> hiddenItems;
// Collects similar ground items
private final Collector<GroundItem, ?, Map<GroundItem.GroundItemKey, GroundItem>> groundItemMapCollector = Collectors
.toMap
((item) -> new GroundItem.GroundItemKey(item.getItemId(), item.getLocation()), Function.identity(), (a, b) ->
{
b.setHaPrice(a.getHaPrice() + b.getHaPrice());
b.setGePrice(a.getGePrice() + b.getGePrice());
b.setQuantity(a.getQuantity() + b.getQuantity());
return b;
},
() -> collectedGroundItems);
@Provides
GroundItemsConfig provideConfig(ConfigManager configManager)
{
@@ -125,7 +162,6 @@ public class GroundItemsPlugin extends Plugin
protected void startUp()
{
reset();
mouseManager.registerMouseListener(inputListener);
keyManager.registerKeyListener(inputListener);
}
@@ -135,6 +171,14 @@ public class GroundItemsPlugin extends Plugin
{
mouseManager.unregisterMouseListener(inputListener);
keyManager.unregisterKeyListener(inputListener);
groundItems.clear();
collectedGroundItems.clear();
highlightedItems.invalidateAll();
highlightedItems = null;
hiddenItems.invalidateAll();
hiddenItems = null;
hiddenItemList = null;
highlightedItemsList = null;
}
@Subscribe
@@ -146,6 +190,136 @@ public class GroundItemsPlugin extends Plugin
}
}
@Subscribe
public void onGameStateChanged(final GameStateChanged event)
{
if (event.getGameState() == GameState.LOGGED_IN)
{
groundItems.clear();
collectedGroundItems.clear();
}
}
@Subscribe
public void onItemLayerChanged(ItemLayerChanged event)
{
dirty = true;
}
void checkItems()
{
final Player player = client.getLocalPlayer();
if (!dirty || player == null || client.getViewportWidget() == null)
{
return;
}
dirty = false;
final Region region = client.getRegion();
final Tile[][][] tiles = region.getTiles();
final int z = client.getPlane();
final LocalPoint from = player.getLocalLocation();
final int lowerX = Math.max(0, from.getRegionX() - MAX_RANGE);
final int lowerY = Math.max(0, from.getRegionY() - MAX_RANGE);
final int upperX = Math.min(from.getRegionX() + MAX_RANGE, REGION_SIZE - 1);
final int upperY = Math.min(from.getRegionY() + MAX_RANGE, REGION_SIZE - 1);
groundItems.clear();
for (int x = lowerX; x <= upperX; ++x)
{
for (int y = lowerY; y <= upperY; ++y)
{
Tile tile = tiles[z][x][y];
if (tile == null)
{
continue;
}
ItemLayer itemLayer = tile.getItemLayer();
if (itemLayer == null)
{
continue;
}
Node current = itemLayer.getBottom();
// adds the items on the ground to the ArrayList to be drawn
while (current instanceof Item)
{
final Item item = (Item) current;
// Continue iteration
current = current.getNext();
// Build ground item
final GroundItem groundItem = buildGroundItem(tile, item);
if (groundItem != null)
{
groundItems.add(groundItem);
}
}
}
}
// Group ground items together and sort them properly
collectedGroundItems.clear();
Lists.reverse(groundItems).stream().collect(groundItemMapCollector);
}
@Nullable
private GroundItem buildGroundItem(final Tile tile, final Item item)
{
// Collect the data for the item
final int itemId = item.getId();
final ItemComposition itemComposition = itemManager.getItemComposition(itemId);
final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemId;
final int alchPrice = Math.round(itemComposition.getPrice() * HIGH_ALCHEMY_CONSTANT);
final String name = itemComposition.getName();
final boolean hidden = isHidden(name);
if (!isHotKeyPressed() && hidden)
{
return null;
}
final boolean highlighted = isHighlighted(name);
if (config.showHighlightedOnly() && !isHotKeyPressed() && !highlighted)
{
return null;
}
final GroundItem groundItem = GroundItem.builder()
.id(itemId)
.location(tile.getWorldLocation())
.itemId(realItemId)
.quantity(item.getQuantity())
.name(itemComposition.getName())
.haPrice(alchPrice * item.getQuantity())
.build();
// Set the correct item price
if (realItemId == COINS)
{
groundItem.setHaPrice(item.getQuantity());
groundItem.setGePrice(item.getQuantity());
}
else
{
final ItemPrice itemPrice = itemManager.getItemPriceAsync(realItemId);
groundItem.setGePrice(itemPrice != null ? itemPrice.getPrice() * item.getQuantity() : 0);
}
return groundItem;
}
private void reset()
{
Splitter COMMA_SPLITTER = Splitter.on(Pattern.compile("\\s*,\\s*"));
@@ -165,6 +339,8 @@ public class GroundItemsPlugin extends Plugin
.maximumSize(512L)
.expireAfterAccess(10, TimeUnit.MINUTES)
.build(new WildcardMatchLoader(hiddenItemList));
dirty = true;
}
private ItemPrice getItemPrice(ItemComposition itemComposition)
@@ -219,20 +395,10 @@ public class GroundItemsPlugin extends Plugin
ItemPrice itemPrice = getItemPrice(itemComposition);
int price = itemPrice == null ? itemComposition.getPrice() : itemPrice.getPrice();
int cost = quantity * price;
Color color = overlay.getCostColor(cost, isHighlighted(itemComposition.getName()),
isHidden(itemComposition.getName()));
Color color = null;
if (cost >= GroundItemsOverlay.LOW_VALUE)
{
color = overlay.getCostColor(cost);
}
if (isHighlighted(itemComposition.getName()))
{
color = config.highlightedColor();
}
if (color != null)
if (!color.equals(config.defaultColor()))
{
String hexColor = Integer.toHexString(color.getRGB() & 0xFFFFFF);
String colTag = "<col=" + hexColor + ">";

View File

@@ -38,6 +38,7 @@ import net.runelite.api.events.DecorativeObjectSpawned;
import net.runelite.api.events.GameObjectChanged;
import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.ItemLayerChanged;
import net.runelite.api.events.GroundObjectChanged;
import net.runelite.api.events.GroundObjectDespawned;
import net.runelite.api.events.GroundObjectSpawned;
@@ -256,4 +257,12 @@ public abstract class RSTileMixin implements RSTile
}
}
}
@FieldHook("itemLayer")
@Inject
public void itemLayerChanged(int idx)
{
ItemLayerChanged itemLayerChanged = new ItemLayerChanged(this);
eventBus.post(itemLayerChanged);
}
}