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.
This commit is contained in:
Adam
2021-09-03 20:08:33 -04:00
parent 99100979df
commit c52667a5cc
11 changed files with 355 additions and 223 deletions

View File

@@ -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<NPC> render;
}

View File

@@ -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<NPC, HighlightedNpc> highlightedNpcs;
@Inject
NpcMinimapOverlay(NpcIndicatorsConfig config, NpcIndicatorsPlugin plugin)
NpcMinimapOverlay(Map<NPC, HighlightedNpc> 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<NPC> render = highlightedNpc.getRender();
if (render != null && !render.test(actor))
{
return;
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright (c) 2018, James Swindle <wilingua@gmail.com>
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* 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<NPC, HighlightedNpc> highlightedNpcs;
NpcOverlay(Client client, ModelOutlineRenderer modelOutlineRenderer, Map<NPC, HighlightedNpc> 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<NPC> 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);
}
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2018, James Swindle <wilingua@gmail.com>
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* 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<Function<NPC, HighlightedNpc>> highlightFunctions = new ArrayList<>();
private final Map<NPC, HighlightedNpc> 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<NPC, HighlightedNpc> 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<NPC, HighlightedNpc> 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<NPC, HighlightedNpc> f : highlightFunctions)
{
HighlightedNpc highlightedNpc = f.apply(npc);
if (highlightedNpc != null)
{
highlightedNpcs.put(npc, highlightedNpc);
continue outer;
}
}
}
});
}
public void registerHighlighter(Function<NPC, HighlightedNpc> p)
{
highlightFunctions.add(p);
rebuild();
}
public void unregisterHighlighter(Function<NPC, HighlightedNpc> p)
{
highlightFunctions.remove(p);
rebuild();
}
}

View File

@@ -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<NPC, HighlightedNpc> 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

View File

@@ -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<Function<NPC, HighlightedNpc>> higlightPredicates = new ArrayList<>();
private final Function<NPC, HighlightedNpc> 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<NPC, HighlightedNpc> 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<NPC, HighlightedNpc> 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<NPC, HighlightedNpc> 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<NPC, HighlightedNpc> p)
{
higlightPredicates.add(p);
}
@Override
public void unregisterHighlighter(Function<NPC, HighlightedNpc> p)
{
higlightPredicates.remove(p);
}
}

View File

@@ -1,35 +0,0 @@
/*
* Copyright (c) 2021, Adam <Adam@sigterm.info>
* 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<NPC, HighlightedNpc> p);
void unregisterHighlighter(Function<NPC, HighlightedNpc> p);
void rebuild();
}

View File

@@ -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)

View File

@@ -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<NPC> 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()

View File

@@ -78,6 +78,7 @@ public class NpcIndicatorsPluginTest
public void setUp()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
when(npcIndicatorsConfig.highlightColor()).thenReturn(Color.RED);
}
@Test

View File

@@ -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;