grounditems: add numerical despawn timers
This commit is contained in:
@@ -31,6 +31,7 @@ import net.runelite.client.config.ConfigGroup;
|
|||||||
import net.runelite.client.config.ConfigItem;
|
import net.runelite.client.config.ConfigItem;
|
||||||
import net.runelite.client.config.Units;
|
import net.runelite.client.config.Units;
|
||||||
import net.runelite.client.config.ConfigSection;
|
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.HighlightTier;
|
||||||
import net.runelite.client.plugins.grounditems.config.ItemHighlightMode;
|
import net.runelite.client.plugins.grounditems.config.ItemHighlightMode;
|
||||||
import net.runelite.client.plugins.grounditems.config.MenuHighlightMode;
|
import net.runelite.client.plugins.grounditems.config.MenuHighlightMode;
|
||||||
@@ -375,13 +376,13 @@ public interface GroundItemsConfig extends Config
|
|||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "groundItemTimers",
|
keyName = "groundItemTimers",
|
||||||
name = "Show despawn timers",
|
name = "Despawn timer",
|
||||||
description = "Shows despawn timers for items you've dropped and received as loot",
|
description = "Shows despawn timers for items you've dropped and received as loot",
|
||||||
position = 28
|
position = 28
|
||||||
)
|
)
|
||||||
default boolean groundItemTimers()
|
default DespawnTimerMode groundItemTimers()
|
||||||
{
|
{
|
||||||
return false;
|
return DespawnTimerMode.OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import net.runelite.api.Point;
|
|||||||
import net.runelite.api.coords.LocalPoint;
|
import net.runelite.api.coords.LocalPoint;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import static net.runelite.client.plugins.grounditems.GroundItemsPlugin.MAX_QUANTITY;
|
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 static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.MENU;
|
||||||
import net.runelite.client.plugins.grounditems.config.PriceDisplayMode;
|
import net.runelite.client.plugins.grounditems.config.PriceDisplayMode;
|
||||||
import net.runelite.client.ui.overlay.Overlay;
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
@@ -175,7 +176,7 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
plugin.setHighlightBoxBounds(null);
|
plugin.setHighlightBoxBounds(null);
|
||||||
|
|
||||||
final boolean onlyShowLoot = config.onlyShowLoot();
|
final boolean onlyShowLoot = config.onlyShowLoot();
|
||||||
final boolean groundItemTimers = config.groundItemTimers();
|
final DespawnTimerMode groundItemTimers = config.groundItemTimers();
|
||||||
final boolean outline = config.textOutline();
|
final boolean outline = config.textOutline();
|
||||||
|
|
||||||
for (GroundItem item : groundItemList)
|
for (GroundItem item : groundItemList)
|
||||||
@@ -347,9 +348,38 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
drawRectangle(graphics, itemHighlightBox, topItem && mouseInHighlightBox ? Color.GREEN : color, highlighted != null, false);
|
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);
|
textComponent.setText(itemString);
|
||||||
@@ -362,12 +392,12 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
return null;
|
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
|
// We can only accurately guess despawn times for our own pvm loot and dropped items
|
||||||
if (groundItem.getLootType() != LootType.PVM && groundItem.getLootType() != LootType.DROPPED)
|
if (groundItem.getLootType() != LootType.PVM && groundItem.getLootType() != LootType.DROPPED)
|
||||||
{
|
{
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loot appears to others after 1 minute, and despawns after 2 minutes
|
// 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();
|
Instant spawnTime = groundItem.getSpawnTime();
|
||||||
if (spawnTime == null)
|
if (spawnTime == null)
|
||||||
{
|
{
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instant despawnTime;
|
Instant despawnTime;
|
||||||
Instant now = Instant.now();
|
Instant now = Instant.now();
|
||||||
Color fillColor;
|
|
||||||
if (client.isInInstancedRegion())
|
if (client.isInInstancedRegion())
|
||||||
{
|
{
|
||||||
// Items in the Kraken instance appear to never despawn?
|
// Items in the Kraken instance appear to never despawn?
|
||||||
if (isInKraken())
|
if (isInKraken())
|
||||||
{
|
{
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
else if (isInKBDorNMZ())
|
else if (isInKBDorNMZ())
|
||||||
{
|
{
|
||||||
@@ -410,7 +439,7 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
// Dropped items in the NMZ instance appear to never despawn?
|
// Dropped items in the NMZ instance appear to never despawn?
|
||||||
if (groundItem.getLootType() == LootType.DROPPED)
|
if (groundItem.getLootType() == LootType.DROPPED)
|
||||||
{
|
{
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -422,8 +451,6 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
{
|
{
|
||||||
despawnTime = spawnTime.plus(DESPAWN_TIME_INSTANCE);
|
despawnTime = spawnTime.plus(DESPAWN_TIME_INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fillColor = PRIVATE_TIMER_COLOR;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -435,21 +462,53 @@ public class GroundItemsOverlay extends Overlay
|
|||||||
{
|
{
|
||||||
despawnTime = spawnTime.plus(DESPAWN_TIME_LOOT);
|
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))
|
if (now.isBefore(spawnTime) || now.isAfter(despawnTime))
|
||||||
{
|
{
|
||||||
// that's weird
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Hydrox6 <ikada@protonmail.ch>
|
||||||
|
* 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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user