From c52667a5cc2e55c7e61e96479c9d59f80772b2ea Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 3 Sep 2021 20:08:33 -0400 Subject: [PATCH] Move npc highlight overlay to core This allows the other plugins which depend on the npc overaly to work when npc highlight plugin is off, while still letting them use the consistent highlight style of the central overlay. --- .../npcoverlay}/HighlightedNpc.java | 13 +- .../npcoverlay}/NpcMinimapOverlay.java | 27 ++-- .../client/game/npcoverlay/NpcOverlay.java | 147 ++++++++++++++++++ .../game/npcoverlay/NpcOverlayService.java | 142 +++++++++++++++++ .../plugins/implings/ImplingsPlugin.java | 20 +-- .../npchighlight/NpcIndicatorsPlugin.java | 95 +++-------- .../npchighlight/NpcIndicatorsService.java | 35 ----- ...eneOverlay.java => NpcRespawnOverlay.java} | 71 +-------- .../client/plugins/slayer/SlayerPlugin.java | 23 +-- .../npchighlight/NpcIndicatorsPluginTest.java | 1 + .../plugins/slayer/SlayerPluginTest.java | 4 +- 11 files changed, 355 insertions(+), 223 deletions(-) rename runelite-client/src/main/java/net/runelite/client/{plugins/npchighlight => game/npcoverlay}/HighlightedNpc.java (85%) rename runelite-client/src/main/java/net/runelite/client/{plugins/npchighlight => game/npcoverlay}/NpcMinimapOverlay.java (85%) create mode 100644 runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcOverlay.java create mode 100644 runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcOverlayService.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsService.java rename runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/{NpcSceneOverlay.java => NpcRespawnOverlay.java} (68%) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/HighlightedNpc.java b/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/HighlightedNpc.java similarity index 85% rename from runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/HighlightedNpc.java rename to runelite-client/src/main/java/net/runelite/client/game/npcoverlay/HighlightedNpc.java index 8622b1091f..f0dc43184c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/HighlightedNpc.java +++ b/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/HighlightedNpc.java @@ -22,10 +22,12 @@ * (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.npchighlight; +package net.runelite.client.game.npcoverlay; import java.awt.Color; +import java.util.function.Predicate; import lombok.Builder; +import lombok.NonNull; import lombok.Value; import net.runelite.api.NPC; @@ -33,13 +35,20 @@ import net.runelite.api.NPC; @Builder public class HighlightedNpc { + @NonNull NPC npc; + @NonNull Color highlightColor; - Color fillColor; + @Builder.Default + Color fillColor = new Color(0, 0, 0, 50); boolean hull; boolean tile; boolean swTile; boolean outline; boolean name; boolean nameOnMinimap; + @Builder.Default + float borderWidth = 2.0f; + int outlineFeather; + Predicate render; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcMinimapOverlay.java similarity index 85% rename from runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcMinimapOverlay.java rename to runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcMinimapOverlay.java index 167040b98f..1639a2f8c9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcMinimapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcMinimapOverlay.java @@ -23,12 +23,13 @@ * (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.npchighlight; +package net.runelite.client.game.npcoverlay; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; -import javax.inject.Inject; +import java.util.Map; +import java.util.function.Predicate; import net.runelite.api.NPC; import net.runelite.api.NPCComposition; import net.runelite.api.Point; @@ -38,16 +39,13 @@ import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.util.Text; -public class NpcMinimapOverlay extends Overlay +class NpcMinimapOverlay extends Overlay { - private final NpcIndicatorsConfig config; - private final NpcIndicatorsPlugin plugin; + private final Map highlightedNpcs; - @Inject - NpcMinimapOverlay(NpcIndicatorsConfig config, NpcIndicatorsPlugin plugin) + NpcMinimapOverlay(Map highlightedNpcs) { - this.config = config; - this.plugin = plugin; + this.highlightedNpcs = highlightedNpcs; setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_WIDGETS); } @@ -55,7 +53,7 @@ public class NpcMinimapOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - for (HighlightedNpc highlightedNpc : plugin.getHighlightedNpcs().values()) + for (HighlightedNpc highlightedNpc : highlightedNpcs.values()) { renderNpcOverlay(graphics, highlightedNpc); } @@ -67,8 +65,13 @@ public class NpcMinimapOverlay extends Overlay { NPC actor = highlightedNpc.getNpc(); NPCComposition npcComposition = actor.getTransformedComposition(); - if (npcComposition == null || !npcComposition.isInteractible() - || (actor.isDead() && config.ignoreDeadNpcs())) + if (npcComposition == null || !npcComposition.isInteractible()) + { + return; + } + + Predicate render = highlightedNpc.getRender(); + if (render != null && !render.test(actor)) { return; } diff --git a/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcOverlay.java b/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcOverlay.java new file mode 100644 index 0000000000..803c44fe26 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcOverlay.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2018, James Swindle + * 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.game.npcoverlay; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Shape; +import java.util.Map; +import java.util.function.Predicate; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.NPCComposition; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +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.outline.ModelOutlineRenderer; +import net.runelite.client.util.Text; + +class NpcOverlay extends Overlay +{ + private final Client client; + private final ModelOutlineRenderer modelOutlineRenderer; + private final Map highlightedNpcs; + + NpcOverlay(Client client, ModelOutlineRenderer modelOutlineRenderer, Map highlightedNpcs) + { + this.client = client; + this.modelOutlineRenderer = modelOutlineRenderer; + this.highlightedNpcs = highlightedNpcs; + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + } + + @Override + public Dimension render(Graphics2D graphics) + { + for (HighlightedNpc highlightedNpc : highlightedNpcs.values()) + { + renderNpcOverlay(graphics, highlightedNpc); + } + + return null; + } + + private void renderNpcOverlay(Graphics2D graphics, HighlightedNpc highlightedNpc) + { + NPC actor = highlightedNpc.getNpc(); + NPCComposition npcComposition = actor.getTransformedComposition(); + if (npcComposition == null || !npcComposition.isInteractible()) + { + return; + } + + Predicate render = highlightedNpc.getRender(); + if (render != null && !render.test(actor)) + { + return; + } + + final Color borderColor = highlightedNpc.getHighlightColor(); + float borderWidth = highlightedNpc.getBorderWidth(); + final Color fillColor = highlightedNpc.getFillColor(); + + if (highlightedNpc.isHull()) + { + Shape objectClickbox = actor.getConvexHull(); + renderPoly(graphics, borderColor, borderWidth, fillColor, objectClickbox); + } + + if (highlightedNpc.isTile()) + { + Polygon tilePoly = actor.getCanvasTilePoly(); + renderPoly(graphics, borderColor, borderWidth, fillColor, tilePoly); + } + + if (highlightedNpc.isSwTile()) + { + int size = npcComposition.getSize(); + LocalPoint lp = actor.getLocalLocation(); + + int x = lp.getX() - ((size - 1) * Perspective.LOCAL_TILE_SIZE / 2); + int y = lp.getY() - ((size - 1) * Perspective.LOCAL_TILE_SIZE / 2); + + Polygon southWestTilePoly = Perspective.getCanvasTilePoly(client, new LocalPoint(x, y)); + + renderPoly(graphics, borderColor, borderWidth, fillColor, southWestTilePoly); + } + + if (highlightedNpc.isOutline()) + { + modelOutlineRenderer.drawOutline(actor, (int) highlightedNpc.getBorderWidth(), borderColor, highlightedNpc.getOutlineFeather()); + } + + if (highlightedNpc.isName() && actor.getName() != null) + { + String npcName = Text.removeTags(actor.getName()); + Point textLocation = actor.getCanvasTextLocation(graphics, npcName, actor.getLogicalHeight() + 40); + + if (textLocation != null) + { + OverlayUtil.renderTextLocation(graphics, textLocation, npcName, borderColor); + } + } + } + + private void renderPoly(Graphics2D graphics, Color borderColor, float borderWidth, Color fillColor, Shape polygon) + { + if (polygon != null) + { + graphics.setColor(borderColor); + graphics.setStroke(new BasicStroke(borderWidth)); + graphics.draw(polygon); + graphics.setColor(fillColor); + graphics.fill(polygon); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcOverlayService.java b/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcOverlayService.java new file mode 100644 index 0000000000..a8e01bf489 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/game/npcoverlay/NpcOverlayService.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2018, James Swindle + * 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.game.npcoverlay; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import javax.inject.Inject; +import javax.inject.Singleton; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.events.NpcChanged; +import net.runelite.api.events.NpcDespawned; +import net.runelite.api.events.NpcSpawned; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.EventBus; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.ui.overlay.outline.ModelOutlineRenderer; + +@Singleton +public class NpcOverlayService +{ + private final Client client; + private final ClientThread clientThread; + private final List> highlightFunctions = new ArrayList<>(); + private final Map highlightedNpcs = new HashMap<>(); + + @Inject + private NpcOverlayService(Client client, ClientThread clientThread, + OverlayManager overlayManager, ModelOutlineRenderer modelOutlineRenderer, EventBus eventBus) + { + this.client = client; + this.clientThread = clientThread; + overlayManager.add(new NpcOverlay(client, modelOutlineRenderer, highlightedNpcs)); + overlayManager.add(new NpcMinimapOverlay(highlightedNpcs)); + eventBus.register(this); + } + + @Subscribe( + // Run after plugins, which typically capture NPCs on spawn and reference them in the highlight functions + priority = -1 + ) + private void onNpcSpawned(NpcSpawned npcSpawned) + { + final NPC npc = npcSpawned.getNpc(); + + for (Function f : highlightFunctions) + { + HighlightedNpc highlightedNpc = f.apply(npc); + if (highlightedNpc != null) + { + highlightedNpcs.put(npc, highlightedNpc); + return; + } + } + } + + @Subscribe + private void onNpcDespawned(NpcDespawned npcDespawned) + { + final NPC npc = npcDespawned.getNpc(); + highlightedNpcs.remove(npc); + } + + @Subscribe + private void onNpcChanged(NpcChanged event) + { + final NPC npc = event.getNpc(); + + highlightedNpcs.remove(npc); + + for (Function f : highlightFunctions) + { + HighlightedNpc highlightedNpc = f.apply(npc); + if (highlightedNpc != null) + { + highlightedNpcs.put(npc, highlightedNpc); + return; + } + } + } + + public void rebuild() + { + clientThread.invoke(() -> + { + highlightedNpcs.clear(); + + outer: + for (NPC npc : client.getNpcs()) + { + for (Function f : highlightFunctions) + { + HighlightedNpc highlightedNpc = f.apply(npc); + if (highlightedNpc != null) + { + highlightedNpcs.put(npc, highlightedNpc); + continue outer; + } + } + } + }); + } + + public void registerHighlighter(Function p) + { + highlightFunctions.add(p); + rebuild(); + } + + public void unregisterHighlighter(Function p) + { + highlightFunctions.remove(p); + rebuild(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsPlugin.java index 6b671ae7d3..09a92c8e12 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsPlugin.java @@ -32,16 +32,13 @@ import net.runelite.api.NPC; import net.runelite.api.events.NpcChanged; import net.runelite.api.events.NpcSpawned; import net.runelite.client.Notifier; -import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; +import net.runelite.client.game.npcoverlay.HighlightedNpc; +import net.runelite.client.game.npcoverlay.NpcOverlayService; import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDependency; import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.npchighlight.HighlightedNpc; -import net.runelite.client.plugins.npchighlight.NpcIndicatorsPlugin; -import net.runelite.client.plugins.npchighlight.NpcIndicatorsService; import net.runelite.client.ui.overlay.OverlayManager; @PluginDescriptor( @@ -49,7 +46,6 @@ import net.runelite.client.ui.overlay.OverlayManager; description = "Highlight nearby implings on the minimap and on-screen", tags = {"hunter", "minimap", "overlay", "imp"} ) -@PluginDependency(NpcIndicatorsPlugin.class) public class ImplingsPlugin extends Plugin { @Inject @@ -65,10 +61,7 @@ public class ImplingsPlugin extends Plugin private Notifier notifier; @Inject - private NpcIndicatorsService npcIndicatorsService; - - @Inject - private ClientThread clientThread; + private NpcOverlayService npcOverlayService; public final Function isTarget = (npc) -> { @@ -79,7 +72,6 @@ public class ImplingsPlugin extends Plugin return HighlightedNpc.builder() .npc(npc) .highlightColor(color) - .fillColor(new Color(0, 0, 0, 50)) .tile(true) .name(true) .nameOnMinimap(config.showName()) @@ -98,13 +90,13 @@ public class ImplingsPlugin extends Plugin protected void startUp() { overlayManager.add(overlay); - npcIndicatorsService.registerHighlighter(isTarget); + npcOverlayService.registerHighlighter(isTarget); } @Override protected void shutDown() { - npcIndicatorsService.unregisterHighlighter(isTarget); + npcOverlayService.unregisterHighlighter(isTarget); overlayManager.remove(overlay); } @@ -116,7 +108,7 @@ public class ImplingsPlugin extends Plugin return; } - clientThread.invoke(npcIndicatorsService::rebuild); + npcOverlayService.rebuild(); } @Subscribe diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java index 02e4926088..c2fb671c10 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java @@ -27,7 +27,6 @@ package net.runelite.client.plugins.npchighlight; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; -import com.google.inject.Binder; import com.google.inject.Provides; import java.awt.Color; import java.time.Instant; @@ -66,6 +65,8 @@ import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; +import net.runelite.client.game.npcoverlay.HighlightedNpc; +import net.runelite.client.game.npcoverlay.NpcOverlayService; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.OverlayManager; @@ -79,7 +80,7 @@ import net.runelite.client.util.WildcardMatcher; tags = {"highlight", "minimap", "npcs", "overlay", "respawn", "tags"} ) @Slf4j -public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService +public class NpcIndicatorsPlugin extends Plugin { private static final int MAX_ACTOR_VIEW_RANGE = 15; @@ -104,14 +105,14 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService private OverlayManager overlayManager; @Inject - private NpcSceneOverlay npcSceneOverlay; - - @Inject - private NpcMinimapOverlay npcMinimapOverlay; + private NpcRespawnOverlay npcRespawnOverlay; @Inject private ClientThread clientThread; + @Inject + private NpcOverlayService npcOverlayService; + /** * NPCs to highlight */ @@ -175,7 +176,7 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService */ private boolean skipNextSpawnCheck = false; - private final List> higlightPredicates = new ArrayList<>(); + private final Function isHighlighted = highlightedNpcs::get; @Provides NpcIndicatorsConfig provideConfig(ConfigManager configManager) @@ -183,17 +184,11 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService return configManager.getConfig(NpcIndicatorsConfig.class); } - @Override - public void configure(Binder binder) - { - binder.bind(NpcIndicatorsService.class).toInstance(this); - } - @Override protected void startUp() throws Exception { - overlayManager.add(npcSceneOverlay); - overlayManager.add(npcMinimapOverlay); + npcOverlayService.registerHighlighter(isHighlighted); + overlayManager.add(npcRespawnOverlay); clientThread.invoke(() -> { skipNextSpawnCheck = true; @@ -204,8 +199,8 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService @Override protected void shutDown() throws Exception { - overlayManager.remove(npcSceneOverlay); - overlayManager.remove(npcMinimapOverlay); + npcOverlayService.unregisterHighlighter(isHighlighted); + overlayManager.remove(npcRespawnOverlay); clientThread.invoke(() -> { deadNpcsToDisplay.clear(); @@ -367,10 +362,13 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService } highlightedNpcs.put(npc, highlightedNpc(npc)); } + + npcOverlayService.rebuild(); } else { final String name = npc.getName(); + // this trips a config change which triggers the overlay rebuild updateNpcsToHighlight(name); } @@ -404,24 +402,7 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService memorizeNpc(npc); spawnedNpcsThisTick.add(npc); } - return; } - - for (Function predicate : higlightPredicates) - { - HighlightedNpc highlightedNpc = predicate.apply(npc); - if (highlightedNpc != null) - { - highlightedNpcs.put(npc, highlightedNpc); - if (!client.isInInstancedRegion()) - { - memorizeNpc(npc); - spawnedNpcsThisTick.add(npc); - } - return; - } - } - } @Subscribe @@ -454,17 +435,6 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService || highlightMatchesNPCName(npcName)) { highlightedNpcs.put(npc, highlightedNpc(npc)); - return; - } - - for (Function predicate : higlightPredicates) - { - HighlightedNpc highlightedNpc = predicate.apply(npc); - if (highlightedNpc != null) - { - highlightedNpcs.put(npc, highlightedNpc); - return; - } } } @@ -572,8 +542,7 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService return Text.fromCSV(configNpcs); } - @Override - public void rebuild() + void rebuild() { highlights = getHighlights(); highlightedNpcs.clear(); @@ -586,7 +555,6 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService return; } - outer: for (NPC npc : client.getNpcs()) { final String npcName = npc.getName(); @@ -612,23 +580,11 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService continue; } - for (Function predicate : higlightPredicates) - { - HighlightedNpc highlightedNpc = predicate.apply(npc); - if (highlightedNpc != null) - { - if (!client.isInInstancedRegion()) - { - memorizeNpc(npc); - } - highlightedNpcs.put(npc, highlightedNpc); - continue outer; - } - } - // NPC is not highlighted memorizedNpcs.remove(npc.getIndex()); } + + npcOverlayService.rebuild(); } private boolean highlightMatchesNPCName(String npcName) @@ -746,18 +702,9 @@ public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService .outline(config.highlightOutline()) .name(config.drawNames()) .nameOnMinimap(config.drawMinimapNames()) + .borderWidth((float) config.borderWidth()) + .outlineFeather(config.outlineFeather()) + .render(n -> !n.isDead() || !config.ignoreDeadNpcs()) .build(); } - - @Override - public void registerHighlighter(Function p) - { - higlightPredicates.add(p); - } - - @Override - public void unregisterHighlighter(Function p) - { - higlightPredicates.remove(p); - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsService.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsService.java deleted file mode 100644 index 440f33fd65..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsService.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2021, 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.npchighlight; - -import java.util.function.Function; -import net.runelite.api.NPC; - -public interface NpcIndicatorsService -{ - void registerHighlighter(Function p); - void unregisterHighlighter(Function p); - void rebuild(); -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcRespawnOverlay.java similarity index 68% rename from runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcRespawnOverlay.java index a13ef58ade..7c2e87dc57 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcRespawnOverlay.java @@ -38,8 +38,6 @@ import java.util.Locale; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.Constants; -import net.runelite.api.NPC; -import net.runelite.api.NPCComposition; import net.runelite.api.Perspective; import net.runelite.api.Point; import net.runelite.api.coords.LocalPoint; @@ -48,10 +46,8 @@ 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.outline.ModelOutlineRenderer; -import net.runelite.client.util.Text; -public class NpcSceneOverlay extends Overlay +class NpcRespawnOverlay extends Overlay { // Anything but white text is quite hard to see since it is drawn on // a dark background @@ -67,16 +63,13 @@ public class NpcSceneOverlay extends Overlay private final Client client; private final NpcIndicatorsConfig config; private final NpcIndicatorsPlugin plugin; - private final ModelOutlineRenderer modelOutlineRenderer; @Inject - NpcSceneOverlay(Client client, NpcIndicatorsConfig config, NpcIndicatorsPlugin plugin, - ModelOutlineRenderer modelOutlineRenderer) + NpcRespawnOverlay(Client client, NpcIndicatorsConfig config, NpcIndicatorsPlugin plugin) { this.client = client; this.config = config; this.plugin = plugin; - this.modelOutlineRenderer = modelOutlineRenderer; setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_SCENE); } @@ -89,11 +82,6 @@ public class NpcSceneOverlay extends Overlay plugin.getDeadNpcsToDisplay().forEach((id, npc) -> renderNpcRespawn(npc, graphics)); } - for (HighlightedNpc highlightedNpc : plugin.getHighlightedNpcs().values()) - { - renderNpcOverlay(graphics, highlightedNpc); - } - return null; } @@ -141,61 +129,6 @@ public class NpcSceneOverlay extends Overlay } } - private void renderNpcOverlay(Graphics2D graphics, HighlightedNpc highlightedNpc) - { - NPC actor = highlightedNpc.getNpc(); - NPCComposition npcComposition = actor.getTransformedComposition(); - if (npcComposition == null || !npcComposition.isInteractible() - || (actor.isDead() && config.ignoreDeadNpcs())) - { - return; - } - - final Color borderColor = highlightedNpc.getHighlightColor(); - final Color fillColor = highlightedNpc.getFillColor(); - - if (highlightedNpc.isHull()) - { - Shape objectClickbox = actor.getConvexHull(); - renderPoly(graphics, borderColor, fillColor, objectClickbox); - } - - if (highlightedNpc.isTile()) - { - Polygon tilePoly = actor.getCanvasTilePoly(); - renderPoly(graphics, borderColor, fillColor, tilePoly); - } - - if (highlightedNpc.isSwTile()) - { - int size = npcComposition.getSize(); - LocalPoint lp = actor.getLocalLocation(); - - int x = lp.getX() - ((size - 1) * Perspective.LOCAL_TILE_SIZE / 2); - int y = lp.getY() - ((size - 1) * Perspective.LOCAL_TILE_SIZE / 2); - - Polygon southWestTilePoly = Perspective.getCanvasTilePoly(client, new LocalPoint(x, y)); - - renderPoly(graphics, borderColor, fillColor, southWestTilePoly); - } - - if (highlightedNpc.isOutline()) - { - modelOutlineRenderer.drawOutline(actor, (int)config.borderWidth(), borderColor, config.outlineFeather()); - } - - if (highlightedNpc.isName() && actor.getName() != null) - { - String npcName = Text.removeTags(actor.getName()); - Point textLocation = actor.getCanvasTextLocation(graphics, npcName, actor.getLogicalHeight() + 40); - - if (textLocation != null) - { - OverlayUtil.renderTextLocation(graphics, textLocation, npcName, borderColor); - } - } - } - private void renderPoly(Graphics2D graphics, Color borderColor, Color fillColor, Shape polygon) { if (polygon != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java index 6983270fa1..41598f00c4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java @@ -83,12 +83,10 @@ import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ChatInput; import net.runelite.client.events.ConfigChanged; import net.runelite.client.game.ItemManager; +import net.runelite.client.game.npcoverlay.HighlightedNpc; +import net.runelite.client.game.npcoverlay.NpcOverlayService; import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDependency; import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.npchighlight.HighlightedNpc; -import net.runelite.client.plugins.npchighlight.NpcIndicatorsPlugin; -import net.runelite.client.plugins.npchighlight.NpcIndicatorsService; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.ColorUtil; @@ -101,7 +99,6 @@ import org.apache.commons.lang3.ArrayUtils; description = "Show additional slayer task related information", tags = {"combat", "notifications", "overlay", "tasks"} ) -@PluginDependency(NpcIndicatorsPlugin.class) @Slf4j public class SlayerPlugin extends Plugin { @@ -176,7 +173,7 @@ public class SlayerPlugin extends Plugin private ChatClient chatClient; @Inject - private NpcIndicatorsService npcIndicatorsService; + private NpcOverlayService npcOverlayService; @Getter(AccessLevel.PACKAGE) private final List targets = new ArrayList<>(); @@ -233,7 +230,7 @@ public class SlayerPlugin extends Plugin protected void startUp() throws Exception { chatCommandManager.registerCommandAsync(TASK_COMMAND_STRING, this::taskLookup, this::taskSubmit); - npcIndicatorsService.registerHighlighter(isTarget); + npcOverlayService.registerHighlighter(isTarget); overlayManager.add(overlay); overlayManager.add(targetWeaknessOverlay); @@ -259,8 +256,7 @@ public class SlayerPlugin extends Plugin protected void shutDown() throws Exception { chatCommandManager.unregisterCommand(TASK_COMMAND_STRING); - npcIndicatorsService.unregisterHighlighter(isTarget); - npcIndicatorsService.rebuild(); + npcOverlayService.unregisterHighlighter(isTarget); overlayManager.remove(overlay); overlayManager.remove(targetWeaknessOverlay); @@ -350,10 +346,7 @@ public class SlayerPlugin extends Plugin setProfileConfig(SlayerConfig.TASK_LOC_KEY, taskLocation); } - @Subscribe( - // Run prior to npc indicators plugin so targets is populated before the isTarget predicate is checked - priority = 1 - ) + @Subscribe public void onNpcSpawned(NpcSpawned npcSpawned) { NPC npc = npcSpawned.getNpc(); @@ -620,7 +613,7 @@ public class SlayerPlugin extends Plugin } else { - clientThread.invoke(npcIndicatorsService::rebuild); + npcOverlayService.rebuild(); } } @@ -746,7 +739,7 @@ public class SlayerPlugin extends Plugin Task task = Task.getTask(name); rebuildTargetNames(task); rebuildTargetList(); - npcIndicatorsService.rebuild(); + npcOverlayService.rebuild(); } private void addCounter() diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPluginTest.java index 8c9c4d4da8..00d3bd2eaa 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPluginTest.java @@ -78,6 +78,7 @@ public class NpcIndicatorsPluginTest public void setUp() { Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + when(npcIndicatorsConfig.highlightColor()).thenReturn(Color.RED); } @Test diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java index d28aefd7c2..c9ebfba6f5 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java @@ -56,7 +56,7 @@ import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.npchighlight.NpcIndicatorsService; +import net.runelite.client.game.npcoverlay.NpcOverlayService; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.http.api.chat.ChatClient; @@ -176,7 +176,7 @@ public class SlayerPluginTest @Mock @Bind - NpcIndicatorsService npcIndicatorsService; + NpcOverlayService npcOverlayService; @Inject SlayerPlugin slayerPlugin;