Merge pull request #3036 from open-osrs/upstream-and-externals

This commit is contained in:
Owain van Brakel
2021-09-07 16:11:41 +02:00
committed by GitHub
18 changed files with 485 additions and 366 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);
}
@@ -66,10 +64,14 @@ public class NpcMinimapOverlay extends Overlay
private void renderNpcOverlay(Graphics2D graphics, HighlightedNpc highlightedNpc)
{
NPC actor = highlightedNpc.getNpc();
String name = Text.removeTags(actor.getName());
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;
}
@@ -80,8 +82,9 @@ public class NpcMinimapOverlay extends Overlay
Color color = highlightedNpc.getHighlightColor();
OverlayUtil.renderMinimapLocation(graphics, minimapLocation, color.darker());
if (highlightedNpc.isNameOnMinimap())
if (highlightedNpc.isNameOnMinimap() && actor.getName() != null)
{
String name = Text.removeTags(actor.getName());
OverlayUtil.renderTextLocation(graphics, minimapLocation, name, color);
}
}

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

@@ -186,9 +186,21 @@ public class OPRSExternalPluginManager
}
public static boolean testRepository(URL url)
{
return testRepository(url, null);
}
public static boolean testRepository(URL url, String pluginsJson)
{
final List<UpdateRepository> repositories = new ArrayList<>();
repositories.add(new DefaultUpdateRepository("repository-testing", url));
if (pluginsJson != null)
{
repositories.add(new DefaultUpdateRepository("repository-testing", url, pluginsJson));
}
else
{
repositories.add(new DefaultUpdateRepository("repository-testing", url));
}
DefaultPluginManager testPluginManager = new DefaultPluginManager(EXTERNALPLUGIN_DIR.toPath());
UpdateManager updateManager = new UpdateManager(testPluginManager, repositories);
@@ -285,7 +297,26 @@ public class OPRSExternalPluginManager
}
}
repositories.add(new DefaultUpdateRepository(id, new URL(url)));
log.info("url: {}", url);
String pluginJson = null;
if (url.contains(".json"))
{
url = url.replace(".json/", ".json");
URL urlObj = new URL(url);
String urlPath = urlObj.getPath();
pluginJson = urlPath.substring(urlPath.lastIndexOf('/') + 1);
}
if (pluginJson == null)
{
repositories.add(new DefaultUpdateRepository(id, new URL(url)));
}
else
{
repositories.add(new DefaultUpdateRepository(id, new URL(url), pluginJson));
}
}
}
catch (ArrayIndexOutOfBoundsException | MalformedURLException e)
@@ -342,7 +373,22 @@ public class OPRSExternalPluginManager
public void addRepository(String key, URL url)
{
DefaultUpdateRepository respository = new DefaultUpdateRepository(key, url);
addRepository(key, url, null);
}
public void addRepository(String key, URL url, String pluginsJson)
{
DefaultUpdateRepository respository;
if (pluginsJson != null)
{
respository = new DefaultUpdateRepository(key, url, pluginsJson);
}
else
{
respository = new DefaultUpdateRepository(key, url);
}
updateManager.addRepository(respository);
eventBus.post(new OPRSRepositoryChanged(key, true));
saveConfig();

View File

@@ -1,67 +0,0 @@
/*
* 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.plugins.corp;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import javax.inject.Inject;
import net.runelite.api.NPC;
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;
class CoreOverlay extends Overlay
{
private final CorpPlugin corpPlugin;
private final CorpConfig config;
@Inject
private CoreOverlay(CorpPlugin corpPlugin, CorpConfig corpConfig)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
this.corpPlugin = corpPlugin;
this.config = corpConfig;
}
@Override
public Dimension render(Graphics2D graphics)
{
NPC core = corpPlugin.getCore();
if (core != null && config.markDarkCore())
{
Polygon canvasTilePoly = core.getCanvasTilePoly();
if (canvasTilePoly != null)
{
OverlayUtil.renderPolygon(graphics, canvasTilePoly, Color.RED.brighter());
}
}
return null;
}
}

View File

@@ -28,9 +28,11 @@ import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("corp")
@ConfigGroup(CorpConfig.GROUP)
public interface CorpConfig extends Config
{
String GROUP = "corp";
@ConfigItem(
keyName = "showDamage",
name = "Show damage overlay",

View File

@@ -25,8 +25,10 @@
package net.runelite.client.plugins.corp;
import com.google.inject.Provides;
import java.awt.Color;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
@@ -50,6 +52,8 @@ import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.QueuedMessage;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
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;
@@ -89,7 +93,24 @@ public class CorpPlugin extends Plugin
private CorpDamageOverlay corpOverlay;
@Inject
private CoreOverlay coreOverlay;
private CorpConfig config;
@Inject
private NpcOverlayService npcOverlayService;
private final Function<NPC, HighlightedNpc> isCore = (npc) ->
{
if (npc == core)
{
return HighlightedNpc.builder()
.npc(npc)
.tile(true)
.highlightColor(Color.RED.brighter())
.render(n -> config.markDarkCore())
.build();
}
return null;
};
@Provides
CorpConfig getConfig(ConfigManager configManager)
@@ -100,15 +121,15 @@ public class CorpPlugin extends Plugin
@Override
protected void startUp() throws Exception
{
npcOverlayService.registerHighlighter(isCore);
overlayManager.add(corpOverlay);
overlayManager.add(coreOverlay);
}
@Override
protected void shutDown() throws Exception
{
npcOverlayService.unregisterHighlighter(isCore);
overlayManager.remove(corpOverlay);
overlayManager.remove(coreOverlay);
corp = core = null;
yourDamage = 0;

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

@@ -208,9 +208,22 @@ public class ExternalPluginManagerPanel extends PluginPanel
}
URL urlActual;
String pluginJson = null;
try
{
urlActual = new URL(url.getText());
String urlText = url.getText();
if (urlText.contains(".json"))
{
urlText = urlText.replace(".json/", ".json");
URL urlObj = new URL(urlText);
String urlPath = urlObj.getPath();
pluginJson = urlPath.substring(urlPath.lastIndexOf('/') + 1);
}
urlActual = new URL(urlText);
}
catch (MalformedURLException e)
{
@@ -219,14 +232,21 @@ public class ExternalPluginManagerPanel extends PluginPanel
return;
}
if (OPRSExternalPluginManager.testRepository(urlActual))
if ((pluginJson == null && OPRSExternalPluginManager.testRepository(urlActual)) || (pluginJson != null && OPRSExternalPluginManager.testRepository(urlActual, pluginJson)))
{
JOptionPane.showMessageDialog(ClientUI.getFrame(), "This doesn't appear to be a valid repository.", "Error!",
JOptionPane.ERROR_MESSAGE);
return;
}
externalPluginManager.addRepository(id.getText(), urlActual);
if (pluginJson == null)
{
externalPluginManager.addRepository(id.getText(), urlActual);
}
else
{
externalPluginManager.addRepository(id.getText(), urlActual, pluginJson);
}
}
@Override

View File

@@ -24,20 +24,18 @@
*/
package net.runelite.client.plugins.runecraft;
import java.awt.Color;
import java.awt.Polygon;
import java.awt.Shape;
import com.google.inject.Inject;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.util.Set;
import net.runelite.api.Client;
import net.runelite.api.DecorativeObject;
import net.runelite.api.NPC;
import net.runelite.api.Point;
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;
class AbyssOverlay extends Overlay
{
@@ -58,44 +56,20 @@ class AbyssOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
if (config.showRifts() && config.showClickBox())
Set<DecorativeObject> abyssObjects = plugin.getAbyssObjects();
if (abyssObjects.isEmpty() || !config.showRifts() || !config.showClickBox())
{
for (DecorativeObject object : plugin.getAbyssObjects())
{
renderRift(graphics, object);
}
return null;
}
if (config.hightlightDarkMage())
for (DecorativeObject object : abyssObjects)
{
highlightDarkMage(graphics);
renderRift(graphics, object);
}
return null;
}
private void highlightDarkMage(Graphics2D graphics)
{
if (!plugin.isDegradedPouchInInventory())
{
return;
}
NPC darkMage = plugin.getDarkMage();
if (darkMage == null)
{
return;
}
Polygon tilePoly = darkMage.getCanvasTilePoly();
if (tilePoly == null)
{
return;
}
OverlayUtil.renderPolygon(graphics, tilePoly, Color.green);
}
private void renderRift(Graphics2D graphics, DecorativeObject object)
{
AbyssRifts rift = AbyssRifts.getRift(object.getId());

View File

@@ -26,10 +26,12 @@ package net.runelite.client.plugins.runecraft;
import com.google.common.collect.ImmutableList;
import com.google.inject.Provides;
import java.awt.Color;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.inject.Inject;
import lombok.AccessLevel;
@@ -47,12 +49,12 @@ import net.runelite.api.events.DecorativeObjectDespawned;
import net.runelite.api.events.DecorativeObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.client.Notifier;
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;
@@ -78,12 +80,8 @@ public class RunecraftPlugin extends Plugin
@Getter(AccessLevel.PACKAGE)
private final Set<AbyssRifts> rifts = new HashSet<>();
@Getter(AccessLevel.PACKAGE)
private boolean degradedPouchInInventory;
@Getter(AccessLevel.PACKAGE)
private NPC darkMage;
@Inject
private OverlayManager overlayManager;
@@ -99,6 +97,11 @@ public class RunecraftPlugin extends Plugin
@Inject
private Notifier notifier;
@Inject
private NpcOverlayService npcOverlayService;
private final Function<NPC, HighlightedNpc> highlightDarkMage = this::highlightDarkMage;
@Provides
RunecraftConfig getConfig(ConfigManager configManager)
{
@@ -108,6 +111,7 @@ public class RunecraftPlugin extends Plugin
@Override
protected void startUp() throws Exception
{
npcOverlayService.registerHighlighter(highlightDarkMage);
overlayManager.add(abyssOverlay);
overlayManager.add(abyssMinimapOverlay);
updateRifts();
@@ -116,10 +120,10 @@ public class RunecraftPlugin extends Plugin
@Override
protected void shutDown() throws Exception
{
npcOverlayService.unregisterHighlighter(highlightDarkMage);
overlayManager.remove(abyssOverlay);
overlayManager.remove(abyssMinimapOverlay);
abyssObjects.clear();
darkMage = null;
degradedPouchInInventory = false;
}
@@ -170,16 +174,9 @@ public class RunecraftPlugin extends Plugin
public void onGameStateChanged(GameStateChanged event)
{
GameState gameState = event.getGameState();
switch (gameState)
if (gameState == GameState.LOADING)
{
case LOADING:
abyssObjects.clear();
break;
case CONNECTION_LOST:
case HOPPING:
case LOGIN_SCREEN:
darkMage = null;
break;
abyssObjects.clear();
}
}
@@ -195,24 +192,18 @@ public class RunecraftPlugin extends Plugin
degradedPouchInInventory = Stream.of(items).anyMatch(i -> DEGRADED_POUCHES.contains(i.getId()));
}
@Subscribe
public void onNpcSpawned(NpcSpawned event)
private HighlightedNpc highlightDarkMage(NPC npc)
{
final NPC npc = event.getNpc();
if (npc.getId() == NpcID.DARK_MAGE)
{
darkMage = npc;
}
}
@Subscribe
public void onNpcDespawned(NpcDespawned event)
{
final NPC npc = event.getNpc();
if (npc == darkMage)
{
darkMage = null;
return HighlightedNpc.builder()
.npc(npc)
.tile(true)
.highlightColor(Color.GREEN)
.render(n -> config.hightlightDarkMage() && degradedPouchInInventory)
.build();
}
return null;
}
private void updateRifts()

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

@@ -79,6 +79,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;