diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 1b3cbe954b..313cbf393f 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -28,6 +28,7 @@ import java.awt.Canvas; import java.util.Arrays; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.rs.api.ItemComposition; public class Client { @@ -187,6 +188,11 @@ public class Client return new Region(this, client.getRegion()); } + public ItemComposition getItemDefinition(int id) + { + return client.getItemDefinition(id); + } + public int getBaseX() { return client.getBaseX(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java index b898cae92f..bfb9c22f88 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java @@ -39,6 +39,7 @@ import net.runelite.client.plugins.clanchat.ClanChat; import net.runelite.client.plugins.config.ConfigPlugin; import net.runelite.client.plugins.devtools.DevTools; import net.runelite.client.plugins.fpsinfo.FPS; +import net.runelite.client.plugins.grounditems.GroundItems; import net.runelite.client.plugins.hiscore.Hiscore; import net.runelite.client.plugins.idlenotifier.IdleNotifier; import net.runelite.client.plugins.mousehighlight.MouseHighlight; @@ -79,6 +80,7 @@ public class PluginManager plugins.add(new Zulrah()); plugins.add(new AccountPlugin()); plugins.add(new ConfigPlugin()); + plugins.add(new GroundItems()); if (RuneLite.getOptions().has("developer-mode")) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItems.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItems.java new file mode 100644 index 0000000000..ca3cfac9fe --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItems.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, Aria + * 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 net.runelite.client.RuneLite; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.ui.overlay.Overlay; + +public class GroundItems extends Plugin +{ + private final GroundItemsConfig config = RuneLite.getRunelite().getConfigManager() + .getConfig(GroundItemsConfig.class); + + private final Overlay overlay = new GroundItemsOverlay(this); + + @Override + protected void startUp() + { + + } + + @Override + public Overlay getOverlay() + { + return overlay; + } + + @Override + protected void shutDown() + { + + } + + public GroundItemsConfig getConfig() + { + return config; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java new file mode 100644 index 0000000000..4ba325e4dd --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017, Aria + * 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 net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup( + keyName = "grounditems", + name = "Ground Items", + description = "Configuration for the ground items plugin" +) +public interface GroundItemsConfig +{ + @ConfigItem( + keyName = "enabled", + name = "Enabled", + description = "Configures whether or not item names/quantities are displayed" + ) + + default boolean enabled() + { + return true; + } +} 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 new file mode 100644 index 0000000000..bd802e30fa --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2017, Aria + * 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.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.Item; +import net.runelite.api.ItemLayer; +import net.runelite.api.Node; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.api.Region; +import net.runelite.api.Tile; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.RuneLite; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.rs.api.ItemComposition; + +public class GroundItemsOverlay extends Overlay +{ + private static final int REGION_SIZE = 104; + // 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 between the player and the item. + private static final int MAX_RANGE = 2400; + // The 15 pixel gap between each drawn ground item. + private static final int STRING_GAP = 15; + + private final Client client = RuneLite.getClient(); + private final GroundItemsConfig config; + private final StringBuilder itemStringBuilder = new StringBuilder(); + + public GroundItemsOverlay(GroundItems plugin) + { + super(OverlayPosition.DYNAMIC); + this.config = plugin.getConfig(); + } + + @Override + public Dimension render(Graphics2D graphics) + { + // won't draw if not logged in + if (client.getGameState() != GameState.LOGGED_IN || !config.enabled()) + { + return null; + } + + Widget bank = client.getWidget(WidgetInfo.BANK_ITEM_CONTAINER); + if (bank != null && !bank.isHidden()) + { + return null; + } + + Region region = client.getRegion(); + Tile[][][] tiles = region.getTiles(); + FontMetrics fm = graphics.getFontMetrics(); + + Player player = client.getLocalPlayer(); + if (player == null) + { + return null; + } + + int z = client.getPlane(); + + for (int x = 0; x < REGION_SIZE; x++) + { + for (int y = 0; y < REGION_SIZE; y++) + { + Tile tile = tiles[z][x][y]; + if (tile == null) + { + continue; + } + + ItemLayer itemLayer = tile.getItemLayer(); + if (itemLayer == null) + { + continue; + } + + if (player.getLocalLocation().distanceTo(itemLayer.getLocalLocation()) >= MAX_RANGE) + { + continue; + } + + Node current = itemLayer.getBottom(); + Map 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(); + + Integer currentQuantity = items.get(itemId); + if (currentQuantity == null) + { + items.put(itemId, itemQuantity); + } + else + { + items.put(itemId, currentQuantity + itemQuantity); + } + + current = current.getNext(); + } + + // The bottom item is drawn first + List itemIds = new ArrayList<>(items.keySet()); + Collections.reverse(itemIds); + + for (int i = 0; i < itemIds.size(); ++i) + { + int itemId = itemIds.get(i); + int quantity = items.get(itemId); + ItemComposition item = client.getItemDefinition(itemId); + + if (item == null) + { + continue; + } + + itemStringBuilder.append(item.getName()); + if (quantity > 1) + { + if (quantity >= MAX_QUANTITY) + { + itemStringBuilder.append(" (Lots!)"); + } + else + { + itemStringBuilder.append(" (").append(quantity).append(")"); + } + } + + String itemString = itemStringBuilder.toString(); + itemStringBuilder.setLength(0); + + Point point = itemLayer.getCanvasLocation(); + // if the item is offscreen, don't bother drawing it + if (point == null) + { + continue; + } + + int screenX = point.getX() + 2 - (fm.stringWidth(itemString) / 2); + + // Drawing the shadow for the text, 1px on both x and y + graphics.setColor(Color.BLACK); + graphics.drawString(itemString, screenX + 1, point.getY() - (STRING_GAP * i) + 1); + // Drawing the text itself + graphics.setColor(Color.WHITE); + graphics.drawString(itemString, screenX, point.getY() - (STRING_GAP * i)); + } + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlight.java b/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlight.java index 096774360e..f7a8c815ea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlight.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlight.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Aria + * Copyright (c) 2017, Aria * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java index c2ed48366a..e8a1b95c2c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Aria + * Copyright (c) 2017, Aria * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/runescape-api/src/main/java/net/runelite/rs/api/Client.java b/runescape-api/src/main/java/net/runelite/rs/api/Client.java index e7efe94158..ea6919c25a 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/Client.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/Client.java @@ -193,6 +193,9 @@ public interface Client extends GameEngine @Import("itemContainers") XHashTable getItemContainers(); + @Import("getItemDefinition") + ItemComposition getItemDefinition(int itemId); + @Import("componentTable") XHashTable getComponentTable();