From 8868d71c10d378ea972b398f9b8a9e7656c1328f Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Tue, 3 Nov 2020 09:27:36 +0000 Subject: [PATCH] grounditems: add numerical despawn timers --- .../grounditems/GroundItemsConfig.java | 7 +- .../grounditems/GroundItemsOverlay.java | 101 ++++++++++++++---- .../grounditems/config/DespawnTimerMode.java | 33 ++++++ 3 files changed, 117 insertions(+), 24 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/DespawnTimerMode.java 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 index 61dbfb4447..43ce88dd2e 100644 --- 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 @@ -31,6 +31,7 @@ import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; import net.runelite.client.config.Units; import net.runelite.client.config.ConfigSection; +import net.runelite.client.plugins.grounditems.config.DespawnTimerMode; import net.runelite.client.plugins.grounditems.config.HighlightTier; import net.runelite.client.plugins.grounditems.config.ItemHighlightMode; import net.runelite.client.plugins.grounditems.config.MenuHighlightMode; @@ -375,13 +376,13 @@ public interface GroundItemsConfig extends Config @ConfigItem( keyName = "groundItemTimers", - name = "Show despawn timers", + name = "Despawn timer", description = "Shows despawn timers for items you've dropped and received as loot", position = 28 ) - default boolean groundItemTimers() + default DespawnTimerMode groundItemTimers() { - return false; + return DespawnTimerMode.OFF; } @ConfigItem( 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 fd22bbe164..ec1d0527c2 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 @@ -47,6 +47,7 @@ import net.runelite.api.Point; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.grounditems.GroundItemsPlugin.MAX_QUANTITY; +import net.runelite.client.plugins.grounditems.config.DespawnTimerMode; import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.MENU; import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; import net.runelite.client.ui.overlay.Overlay; @@ -175,7 +176,7 @@ public class GroundItemsOverlay extends Overlay plugin.setHighlightBoxBounds(null); final boolean onlyShowLoot = config.onlyShowLoot(); - final boolean groundItemTimers = config.groundItemTimers(); + final DespawnTimerMode groundItemTimers = config.groundItemTimers(); final boolean outline = config.textOutline(); for (GroundItem item : groundItemList) @@ -347,9 +348,38 @@ public class GroundItemsOverlay extends Overlay drawRectangle(graphics, itemHighlightBox, topItem && mouseInHighlightBox ? Color.GREEN : color, highlighted != null, false); } - if (groundItemTimers || plugin.isHotKeyPressed()) + // When the hotkey is pressed the hidden/highlight boxes are drawn to the right of the text, + // so always draw the pie since it is on the left hand side. + if (groundItemTimers == DespawnTimerMode.PIE || plugin.isHotKeyPressed()) { - drawTimerOverlay(graphics, textX, textY, item); + drawTimerPieOverlay(graphics, textX, textY, item); + } + else if (groundItemTimers == DespawnTimerMode.SECONDS || groundItemTimers == DespawnTimerMode.TICKS) + { + Instant despawnTime = calculateDespawnTime(item); + Color timerColor = getItemTimerColor(item); + if (despawnTime != null && timerColor != null) + { + long despawnTimeMillis = despawnTime.toEpochMilli() - Instant.now().toEpochMilli(); + final String timerText; + if (groundItemTimers == DespawnTimerMode.SECONDS) + { + timerText = String.format(" - %.1f", despawnTimeMillis / 1000f); + } + else // TICKS + { + timerText = String.format(" - %d", despawnTimeMillis / 600); + } + + // The timer text is drawn separately to have its own color, and is intentionally not included + // in the getCanvasTextLocation() call because the timer text can change per frame and we do not + // use a monospaced font, which causes the text location on screen to jump around slightly each frame. + textComponent.setText(timerText); + textComponent.setColor(timerColor); + textComponent.setOutline(outline); + textComponent.setPosition(new java.awt.Point(textX + fm.stringWidth(itemString), textY)); + textComponent.render(graphics); + } } textComponent.setText(itemString); @@ -362,12 +392,12 @@ public class GroundItemsOverlay extends Overlay return null; } - private void drawTimerOverlay(Graphics2D graphics, int textX, int textY, GroundItem groundItem) + private Instant calculateDespawnTime(GroundItem groundItem) { // We can only accurately guess despawn times for our own pvm loot and dropped items if (groundItem.getLootType() != LootType.PVM && groundItem.getLootType() != LootType.DROPPED) { - return; + return null; } // Loot appears to others after 1 minute, and despawns after 2 minutes @@ -377,18 +407,17 @@ public class GroundItemsOverlay extends Overlay Instant spawnTime = groundItem.getSpawnTime(); if (spawnTime == null) { - return; + return null; } Instant despawnTime; Instant now = Instant.now(); - Color fillColor; if (client.isInInstancedRegion()) { // Items in the Kraken instance appear to never despawn? if (isInKraken()) { - return; + return null; } else if (isInKBDorNMZ()) { @@ -410,7 +439,7 @@ public class GroundItemsOverlay extends Overlay // Dropped items in the NMZ instance appear to never despawn? if (groundItem.getLootType() == LootType.DROPPED) { - return; + return null; } else { @@ -422,8 +451,6 @@ public class GroundItemsOverlay extends Overlay { despawnTime = spawnTime.plus(DESPAWN_TIME_INSTANCE); } - - fillColor = PRIVATE_TIMER_COLOR; } else { @@ -435,21 +462,53 @@ public class GroundItemsOverlay extends Overlay { despawnTime = spawnTime.plus(DESPAWN_TIME_LOOT); } - - // If it has not yet been a minute, the item is private - if (spawnTime.plus(1, ChronoUnit.MINUTES).isAfter(now)) - { - fillColor = PRIVATE_TIMER_COLOR; - } - else - { - fillColor = PUBLIC_TIMER_COLOR; - } } if (now.isBefore(spawnTime) || now.isAfter(despawnTime)) { // that's weird + return null; + } + + return despawnTime; + } + + private Color getItemTimerColor(GroundItem groundItem) + { + // We can only accurately guess despawn times for our own pvm loot and dropped items + if (groundItem.getLootType() != LootType.PVM && groundItem.getLootType() != LootType.DROPPED) + { + return null; + } + + final Instant spawnTime = groundItem.getSpawnTime(); + if (spawnTime == null) + { + return null; + } + + final Instant now = Instant.now(); + + // If it has not yet been a minute, the item is private + if (client.isInInstancedRegion() || spawnTime.plus(1, ChronoUnit.MINUTES).isAfter(now)) + { + return PRIVATE_TIMER_COLOR; + } + else + { + return PUBLIC_TIMER_COLOR; + } + } + + private void drawTimerPieOverlay(Graphics2D graphics, int textX, int textY, GroundItem groundItem) + { + Instant now = Instant.now(); + Instant spawnTime = groundItem.getSpawnTime(); + Instant despawnTime = calculateDespawnTime(groundItem); + Color fillColor = getItemTimerColor(groundItem); + + if (spawnTime == null || despawnTime == null || fillColor == null) + { return; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/DespawnTimerMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/DespawnTimerMode.java new file mode 100644 index 0000000000..858bc48754 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/config/DespawnTimerMode.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020, Hydrox6 + * 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.config; + +public enum DespawnTimerMode +{ + OFF, + PIE, + TICKS, + SECONDS +}