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;