From d9ca9f506099695b7cbc7dc5b1ff7c75f5305a71 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 27 Jul 2018 22:57:27 -0400 Subject: [PATCH] fishing plugin: add minnows overlay This shows a progress pie on how much time is left before the minnow moves Co-authored-by: Jacky --- .../client/plugins/fishing/FishingConfig.java | 10 ++++ .../client/plugins/fishing/FishingPlugin.java | 50 ++++++++++++++++++- .../plugins/fishing/FishingSpotOverlay.java | 46 +++++++++++++++-- .../client/plugins/fishing/MinnowSpot.java | 38 ++++++++++++++ 4 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/fishing/MinnowSpot.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java index 8f1871a8a3..40ce4d19c3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java @@ -200,4 +200,14 @@ public interface FishingConfig extends Config { return true; } + + @ConfigItem( + keyName = "showMinnowOverlay", + name = "Show Minnow Movement overlay", + description = "Configures whether to display the minnow progress pie overlay" + ) + default boolean showMinnowOverlay() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java index e5a7fb50b6..743e327b1a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java @@ -28,14 +28,18 @@ package net.runelite.client.plugins.fishing; import com.google.common.eventbus.Subscribe; import com.google.common.primitives.Ints; import com.google.inject.Provides; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; import lombok.AccessLevel; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.NPC; @@ -43,6 +47,7 @@ import net.runelite.api.coords.LocalPoint; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameTick; +import net.runelite.api.events.NpcDespawned; import net.runelite.api.queries.NPCQuery; import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.Plugin; @@ -59,10 +64,14 @@ import net.runelite.client.util.QueryRunner; ) @PluginDependency(XpTrackerPlugin.class) @Singleton +@Slf4j public class FishingPlugin extends Plugin { private final List spotIds = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private Map minnowSpots = new HashMap<>(); + @Getter(AccessLevel.PACKAGE) private NPC[] fishingSpots; @@ -110,6 +119,7 @@ public class FishingPlugin extends Plugin overlayManager.remove(overlay); overlayManager.remove(spotOverlay); overlayManager.remove(fishingSpotMinimapOverlay); + minnowSpots.clear(); } public FishingSession getSession() @@ -199,7 +209,7 @@ public class FishingPlugin extends Plugin } @Subscribe - public void checkSpots(GameTick event) + public void onGameTick(GameTick event) { final LocalPoint cameraPoint = new LocalPoint(client.getCameraX(), client.getCameraY()); @@ -209,5 +219,43 @@ public class FishingPlugin extends Plugin // -1 to make closer things draw last (on top of farther things) Arrays.sort(spots, Comparator.comparing(npc -> -1 * npc.getLocalLocation().distanceTo(cameraPoint))); fishingSpots = spots; + + // process minnows + for (NPC npc : spots) + { + FishingSpot spot = FishingSpot.getSpot(npc.getId()); + + if (spot == null) + { + continue; + } + + if (spot == FishingSpot.MINNOW && config.showMinnowOverlay()) + { + int id = npc.getIndex(); + MinnowSpot minnowSpot = minnowSpots.get(id); + // create the minnow spot if it doesn't already exist + if (minnowSpot == null) + { + minnowSpots.put(id, new MinnowSpot(npc.getWorldLocation(), Instant.now())); + } + // if moved, reset + else if (!minnowSpot.getLoc().equals(npc.getWorldLocation())) + { + minnowSpots.put(id, new MinnowSpot(npc.getWorldLocation(), Instant.now())); + } + } + } + } + + @Subscribe + public void onNpcDespawned(NpcDespawned npcDespawned) + { + NPC npc = npcDespawned.getNpc(); + MinnowSpot minnowSpot = minnowSpots.remove(npc.getIndex()); + if (minnowSpot != null) + { + log.debug("Minnow spot {} despawned", npc); + } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java index 27cb707e6c..573ff86447 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java @@ -28,30 +28,41 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.image.BufferedImage; +import java.time.Duration; +import java.time.Instant; import javax.inject.Inject; +import net.runelite.api.Client; import net.runelite.api.GraphicID; import net.runelite.api.NPC; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; import net.runelite.client.game.ItemManager; 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.OverlayUtil; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; class FishingSpotOverlay extends Overlay { + private static final Duration MINNOW_MOVE = Duration.ofSeconds(15); + private static final Duration MINNOW_WARN = Duration.ofSeconds(3); + private final FishingPlugin plugin; private final FishingConfig config; + private final Client client; + private final ItemManager itemManager; @Inject - ItemManager itemManager; - - @Inject - public FishingSpotOverlay(FishingPlugin plugin, FishingConfig config) + private FishingSpotOverlay(FishingPlugin plugin, FishingConfig config, Client client, ItemManager itemManager) { setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_SCENE); this.plugin = plugin; this.config = config; + this.client = client; + this.itemManager = itemManager; } @Override @@ -73,6 +84,33 @@ class FishingSpotOverlay extends Overlay } Color color = npc.getGraphic() == GraphicID.FLYING_FISH ? Color.RED : Color.CYAN; + + if (spot == FishingSpot.MINNOW && config.showMinnowOverlay()) + { + MinnowSpot minnowSpot = plugin.getMinnowSpots().get(npc.getIndex()); + if (minnowSpot != null) + { + long millisLeft = MINNOW_MOVE.toMillis() - Duration.between(minnowSpot.getTime(), Instant.now()).toMillis(); + if (millisLeft < MINNOW_WARN.toMillis()) + { + color = Color.ORANGE; + } + + LocalPoint localPoint = npc.getLocalLocation(); + Point location = Perspective.worldToCanvas(client, localPoint.getX(), localPoint.getY(), client.getPlane()); + + if (location != null) + { + ProgressPieComponent pie = new ProgressPieComponent(); + pie.setFill(color); + pie.setBorderColor(color); + pie.setPosition(location); + pie.setProgress((float) millisLeft / MINNOW_MOVE.toMillis()); + pie.render(graphics); + } + } + } + if (config.showIcons()) { BufferedImage fishImage = getFishImage(spot); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/MinnowSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/MinnowSpot.java new file mode 100644 index 0000000000..b17270dfee --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/MinnowSpot.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Adam + * 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.fishing; + +import java.time.Instant; +import lombok.AllArgsConstructor; +import lombok.Value; +import net.runelite.api.coords.WorldPoint; + +@AllArgsConstructor +@Value +class MinnowSpot +{ + private final WorldPoint loc; + private final Instant time; +}