From 0a86fe35aff62d24942405490ac8b88b98bc9dcc Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 3 Aug 2021 19:13:52 -0400 Subject: [PATCH 1/9] widgetoverlay: support detached overlays This adds support for moving the wilderness icon layer, which is not in an area near a snap corner. With no preferred location set the overlay adjusts its bounds to the widget bounds and will not adjust the widget position. --- .../net/runelite/api/widgets/WidgetID.java | 1 + .../net/runelite/api/widgets/WidgetInfo.java | 1 + .../runelite/client/ui/overlay/Overlay.java | 7 +++ .../client/ui/overlay/OverlayManager.java | 4 +- .../client/ui/overlay/WidgetOverlay.java | 44 +++++++++++++++++-- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index c51e0ed1eb..097c456d14 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -774,6 +774,7 @@ public class WidgetID static class Pvp { static final int KILLDEATH_RATIO = 26; + static final int WILDERNESS_SKULL_CONTAINER = 44; static final int SKULL_CONTAINER = 45; static final int SAFE_ZONE = 47; static final int WILDERNESS_LEVEL = 50; // this can also be the Deadman Mode "Protection" text diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index 98f66a8b83..52e5961559 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -501,6 +501,7 @@ public enum WidgetInfo SPELL_ARCEUUS_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.ArceuusSpellBook.ARCEUUS_HOME_TELEPORT), SPELL_KOUREND_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.StandardSpellBook.KOUREND_HOME_TELEPORT), + PVP_WILDERNESS_SKULL_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.WILDERNESS_SKULL_CONTAINER), PVP_SKULL_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL_CONTAINER), PVP_WORLD_SAFE_ZONE(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SAFE_ZONE), diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java index 41944b5cd7..14197b90a1 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java @@ -120,4 +120,11 @@ public abstract class Overlay implements LayoutableRenderableEntity { return null; } + + public void reset() + { + setPreferredPosition(null); + setPreferredSize(null); + setPreferredLocation(null); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java index 6e3c770b37..21cb834ca1 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java @@ -289,9 +289,7 @@ public class OverlayManager */ public synchronized void resetOverlay(final Overlay overlay) { - overlay.setPreferredPosition(null); - overlay.setPreferredSize(null); - overlay.setPreferredLocation(null); + overlay.reset(); saveOverlay(overlay); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java index d470bbb242..384acab9d8 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java @@ -30,11 +30,13 @@ import java.awt.Rectangle; import java.util.Arrays; import java.util.Collection; import java.util.Objects; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.Varbits; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +@Slf4j public class WidgetOverlay extends Overlay { public static Collection createOverlays(final Client client) @@ -71,13 +73,15 @@ public class WidgetOverlay extends Overlay new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_RESIZEABLE_CLASSIC, OverlayPosition.CANVAS_TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.TEMPOROSS_STATUS_INDICATOR, OverlayPosition.TOP_LEFT), new WidgetOverlay(client, WidgetInfo.BA_HEAL_TEAMMATES, OverlayPosition.BOTTOM_LEFT), - new WidgetOverlay(client, WidgetInfo.BA_TEAM, OverlayPosition.TOP_RIGHT) + new WidgetOverlay(client, WidgetInfo.BA_TEAM, OverlayPosition.TOP_RIGHT), + new WidgetOverlay(client, WidgetInfo.PVP_WILDERNESS_SKULL_CONTAINER, OverlayPosition.DETACHED) ); } protected final Client client; private final WidgetInfo widgetInfo; private final Rectangle parentBounds = new Rectangle(); + private boolean revalidate; private WidgetOverlay(final Client client, final WidgetInfo widgetInfo, final OverlayPosition overlayPosition) { @@ -107,10 +111,34 @@ public class WidgetOverlay extends Overlay return null; } + assert widget != null; + final Rectangle bounds = getBounds(); - // The widget relative pos is relative to the parent - widget.setRelativeX(bounds.x - parent.x); - widget.setRelativeY(bounds.y - parent.y); + // OverlayRenderer sets the overlay bounds to the preferred location if one is set prior to calling render() + // for detached overlays. + if (getPosition() != OverlayPosition.DETACHED || getPreferredLocation() != null) + { + // The widget relative pos is relative to the parent + widget.setRelativeX(bounds.x - parent.x); + widget.setRelativeY(bounds.y - parent.y); + } + else + { + if (revalidate) + { + revalidate = false; + log.debug("Revalidating {}", widgetInfo); + // Revalidate the widget to reposition it back to its normal location after an overlay reset + widget.revalidate(); + } + + // Update the overlay bounds to the widget bounds so the drag overlay renders correctly. + // Note OverlayManager uses original bounds reference to render managing mode and for + // onMouseOver, so update the existing bounds vs. replacing the reference. + Rectangle widgetBounds = widget.getBounds(); + bounds.setBounds(widgetBounds.x, widgetBounds.y, widgetBounds.width, widgetBounds.height); + } + return new Dimension(widget.getWidth(), widget.getHeight()); } @@ -152,6 +180,14 @@ public class WidgetOverlay extends Overlay return getParentBounds(widget); } + @Override + public void reset() + { + super.reset(); + // Revalidate must be called on the client thread, so defer til next frame + revalidate = true; + } + private static class XpTrackerWidgetOverlay extends WidgetOverlay { private XpTrackerWidgetOverlay(Client client, WidgetInfo widgetInfo, OverlayPosition overlayPosition) From b23a3108322e90b9f6783bdf6e8bc33a74725964 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Fri, 6 Aug 2021 00:19:12 -0600 Subject: [PATCH 2/9] itemstats: remove quest field this has always been unused and isn't particularly useful to us anyway --- .../main/java/net/runelite/http/api/item/ItemStats.java | 3 +-- .../client/plugins/itemstats/ItemStatOverlay.java | 2 +- .../client/plugins/itemstats/ItemStatOverlayTest.java | 8 ++++---- .../runelite/client/plugins/prayer/PrayerPluginTest.java | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/http-api/src/main/java/net/runelite/http/api/item/ItemStats.java b/http-api/src/main/java/net/runelite/http/api/item/ItemStats.java index 55a1bf76dd..5b86dd336d 100644 --- a/http-api/src/main/java/net/runelite/http/api/item/ItemStats.java +++ b/http-api/src/main/java/net/runelite/http/api/item/ItemStats.java @@ -30,7 +30,6 @@ import lombok.Value; @Value public class ItemStats { - private boolean quest; private boolean equipable; private double weight; @SerializedName("ge_limit") @@ -79,7 +78,7 @@ public class ItemStats newEquipment = equipment; } - return new ItemStats(quest, equipable, newWeight, 0, newEquipment); + return new ItemStats(equipable, newWeight, 0, newEquipment); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java index ff3922fd92..4465c0b338 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java @@ -55,7 +55,7 @@ public class ItemStatOverlay extends Overlay { // Unarmed attack speed is 4 @VisibleForTesting - static final ItemStats UNARMED = new ItemStats(false, true, 0, 0, + static final ItemStats UNARMED = new ItemStats(true, 0, 0, ItemEquipmentStats.builder() .aspeed(4) .build()); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatOverlayTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatOverlayTest.java index 3151ff91c1..f9bc39ba80 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatOverlayTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/itemstats/ItemStatOverlayTest.java @@ -53,7 +53,7 @@ import org.mockito.junit.MockitoJUnitRunner; public class ItemStatOverlayTest { // Weapon definitions - private static final ItemStats ABYSSAL_DAGGER = new ItemStats(false, true, 0.453, 8, + private static final ItemStats ABYSSAL_DAGGER = new ItemStats(true, 0.453, 8, ItemEquipmentStats.builder() .slot(EquipmentInventorySlot.WEAPON.getSlotIdx()) .isTwoHanded(false) @@ -65,7 +65,7 @@ public class ItemStatOverlayTest .str(75) .aspeed(4) .build()); - private static final ItemStats KATANA = new ItemStats(false, true, 0, 8, + private static final ItemStats KATANA = new ItemStats(true, 0, 8, ItemEquipmentStats.builder() .slot(EquipmentInventorySlot.WEAPON.getSlotIdx()) .isTwoHanded(true) @@ -78,7 +78,7 @@ public class ItemStatOverlayTest .str(40) .aspeed(4) .build()); - private static final ItemStats BLOWPIPE = new ItemStats(false, true, 0, 0, + private static final ItemStats BLOWPIPE = new ItemStats(true, 0, 0, ItemEquipmentStats.builder() .slot(EquipmentInventorySlot.WEAPON.getSlotIdx()) .isTwoHanded(true) @@ -86,7 +86,7 @@ public class ItemStatOverlayTest .rstr(40) .aspeed(3) .build()); - private static final ItemStats HEAVY_BALLISTA = new ItemStats(false, true, 4, 8, + private static final ItemStats HEAVY_BALLISTA = new ItemStats(true, 4, 8, ItemEquipmentStats.builder() .slot(EquipmentInventorySlot.WEAPON.getSlotIdx()) .isTwoHanded(true) diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/prayer/PrayerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/prayer/PrayerPluginTest.java index c6d001f1a8..db2581bc90 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/prayer/PrayerPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/prayer/PrayerPluginTest.java @@ -55,7 +55,7 @@ import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class PrayerPluginTest { - private static final ItemStats HIGH_PRAYER_BONUS_WEAPON = new ItemStats(false, false, 0, 0, + private static final ItemStats HIGH_PRAYER_BONUS_WEAPON = new ItemStats(false, 0, 0, ItemEquipmentStats.builder() .slot(EquipmentInventorySlot.WEAPON.getSlotIdx()) .prayer(50) From 24932cc9fc71b7563552d3a1b81832be69cb5ad2 Mon Sep 17 00:00:00 2001 From: JoshS Date: Sat, 7 Aug 2021 11:39:22 -0400 Subject: [PATCH 3/9] skill calc: add Magic Essence Potion --- .../client/plugins/skillcalculator/skill_herblore.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_herblore.json b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_herblore.json index 6e3c4c088b..d91f14eccf 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_herblore.json +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_herblore.json @@ -192,6 +192,12 @@ "name": "Super Strength (3)", "xp": 125 }, + { + "level": 57, + "icon": 9022, + "name": "Magic Essence Potion (3)", + "xp": 130 + }, { "level": 59, "icon": 3000, From a3350a61c835db55507c178a20245856a72ba804 Mon Sep 17 00:00:00 2001 From: BenMortensenTTS Date: Sat, 29 May 2021 15:21:08 -0700 Subject: [PATCH 4/9] loot tracker: add rogues' chest --- .../client/plugins/loottracker/LootTrackerPlugin.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index bdc4d738d7..634a1fcc77 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -147,6 +147,7 @@ public class LootTrackerPlugin extends Plugin // Chest loot handling private static final String CHEST_LOOTED_MESSAGE = "You find some treasure in the chest!"; + private static final Pattern ROGUES_CHEST_PATTERN = Pattern.compile("You find (a|some)([a-z\\s]*) inside."); private static final Pattern LARRAN_LOOTED_PATTERN = Pattern.compile("You have opened Larran's (big|small) chest .*"); // Used by Stone Chest, Isle of Souls chest, Dark Chest private static final String OTHER_CHEST_LOOTED_MESSAGE = "You steal some loot from the chest."; @@ -167,6 +168,7 @@ public class LootTrackerPlugin extends Plugin put(7323, "Grubby Chest"). put(8593, "Isle of Souls Chest"). put(7827, "Dark Chest"). + put(13117, "Rogues' Chest"). build(); // Shade chest loot handling @@ -646,7 +648,7 @@ public class LootTrackerPlugin extends Plugin if (message.equals(CHEST_LOOTED_MESSAGE) || message.equals(OTHER_CHEST_LOOTED_MESSAGE) || message.equals(DORGESH_KAAN_CHEST_LOOTED_MESSAGE) || message.startsWith(GRUBBY_CHEST_LOOTED_MESSAGE) - || LARRAN_LOOTED_PATTERN.matcher(message).matches()) + || LARRAN_LOOTED_PATTERN.matcher(message).matches() || ROGUES_CHEST_PATTERN.matcher(message).matches()) { final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID(); if (!CHEST_EVENT_TYPES.containsKey(regionID)) From c7b444d8926e994a9f2c32b80e69a0d3b227136e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 7 Aug 2021 15:18:45 -0400 Subject: [PATCH 5/9] slayer plugin: use npchiglight for task highlights --- .../npchighlight/NpcIndicatorsPlugin.java | 62 ++++++++++- .../npchighlight/NpcIndicatorsService.java | 35 ++++++ .../client/plugins/slayer/SlayerConfig.java | 14 --- .../client/plugins/slayer/SlayerPlugin.java | 105 +++++++++++------- .../plugins/slayer/TargetClickboxOverlay.java | 85 -------------- .../plugins/slayer/TargetMinimapOverlay.java | 80 ------------- .../plugins/slayer/TargetWeaknessOverlay.java | 2 +- .../client/plugins/PluginManagerTest.java | 35 +++--- .../npchighlight/NpcIndicatorsPluginTest.java | 8 +- .../plugins/slayer/SlayerPluginTest.java | 13 ++- 10 files changed, 193 insertions(+), 246 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsService.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetClickboxOverlay.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetMinimapOverlay.java 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 a68a76d184..de84c15666 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,6 +27,7 @@ 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; @@ -38,6 +39,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; import javax.inject.Inject; import lombok.AccessLevel; import lombok.Getter; @@ -77,7 +79,7 @@ import net.runelite.client.util.WildcardMatcher; tags = {"highlight", "minimap", "npcs", "overlay", "respawn", "tags"} ) @Slf4j -public class NpcIndicatorsPlugin extends Plugin +public class NpcIndicatorsPlugin extends Plugin implements NpcIndicatorsService { private static final int MAX_ACTOR_VIEW_RANGE = 15; @@ -173,12 +175,20 @@ public class NpcIndicatorsPlugin extends Plugin */ private boolean skipNextSpawnCheck = false; + private final List> higlightPredicates = new ArrayList<>(); + @Provides NpcIndicatorsConfig provideConfig(ConfigManager configManager) { return configManager.getConfig(NpcIndicatorsConfig.class); } + @Override + public void configure(Binder binder) + { + binder.bind(NpcIndicatorsService.class).toInstance(this); + } + @Override protected void startUp() throws Exception { @@ -187,7 +197,7 @@ public class NpcIndicatorsPlugin extends Plugin clientThread.invoke(() -> { skipNextSpawnCheck = true; - rebuildAllNpcs(); + rebuild(); }); } @@ -230,7 +240,7 @@ public class NpcIndicatorsPlugin extends Plugin return; } - clientThread.invoke(this::rebuildAllNpcs); + clientThread.invoke(this::rebuild); } @Subscribe @@ -394,7 +404,23 @@ public class NpcIndicatorsPlugin extends Plugin memorizeNpc(npc); spawnedNpcsThisTick.add(npc); } + return; } + + for (Predicate predicate : higlightPredicates) + { + if (predicate.test(npc)) + { + highlightedNpcs.add(npc); + if (!client.isInInstancedRegion()) + { + memorizeNpc(npc); + spawnedNpcsThisTick.add(npc); + } + return; + } + } + } @Subscribe @@ -534,8 +560,8 @@ public class NpcIndicatorsPlugin extends Plugin return Text.fromCSV(configNpcs); } - @VisibleForTesting - void rebuildAllNpcs() + @Override + public void rebuild() { highlights = getHighlights(); highlightedNpcs.clear(); @@ -548,6 +574,7 @@ public class NpcIndicatorsPlugin extends Plugin return; } + outer: for (NPC npc : client.getNpcs()) { final String npcName = npc.getName(); @@ -573,6 +600,19 @@ public class NpcIndicatorsPlugin extends Plugin continue; } + for (Predicate predicate : higlightPredicates) + { + if (predicate.test(npc)) + { + if (!client.isInInstancedRegion()) + { + memorizeNpc(npc); + } + highlightedNpcs.add(npc); + continue outer; + } + } + // NPC is not highlighted memorizedNpcs.remove(npc.getIndex()); } @@ -680,4 +720,16 @@ public class NpcIndicatorsPlugin extends Plugin despawnedNpcsThisTick.clear(); teleportGraphicsObjectSpawnedThisTick.clear(); } + + @Override + public void registerHighlighter(Predicate p) + { + higlightPredicates.add(p); + } + + @Override + public void unregisterHighlighter(Predicate 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 new file mode 100644 index 0000000000..43a3b91694 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsService.java @@ -0,0 +1,35 @@ +/* + * 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.Predicate; +import net.runelite.api.NPC; + +public interface NpcIndicatorsService +{ + void registerHighlighter(Predicate p); + void unregisterHighlighter(Predicate p); + void rebuild(); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java index d16f96fa58..258ea51b17 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java @@ -25,8 +25,6 @@ */ package net.runelite.client.plugins.slayer; -import java.awt.Color; -import net.runelite.client.config.Alpha; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; @@ -101,18 +99,6 @@ public interface SlayerConfig extends Config return false; } - @Alpha - @ConfigItem( - position = 6, - keyName = "targetColor", - name = "Target Color", - description = "Color of the highlighted targets" - ) - default Color getTargetColor() - { - return Color.RED; - } - @ConfigItem( position = 7, keyName = "weaknessPrompt", 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 8cc18aa550..729debeb25 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 @@ -39,9 +39,11 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; +import javax.inject.Named; import joptsimple.internal.Strings; import lombok.AccessLevel; import lombok.Getter; @@ -60,6 +62,7 @@ import static net.runelite.api.Skill.SLAYER; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ActorDeath; import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.CommandExecuted; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.HitsplatApplied; @@ -81,18 +84,23 @@ import net.runelite.client.events.ChatInput; import net.runelite.client.events.ConfigChanged; import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDependency; import net.runelite.client.plugins.PluginDescriptor; +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; import net.runelite.client.util.Text; import net.runelite.http.api.chat.ChatClient; +import org.apache.commons.lang3.ArrayUtils; @PluginDescriptor( name = "Slayer", description = "Show additional slayer task related information", tags = {"combat", "notifications", "overlay", "tasks"} ) +@PluginDependency(NpcIndicatorsPlugin.class) @Slf4j public class SlayerPlugin extends Plugin { @@ -151,15 +159,9 @@ public class SlayerPlugin extends Plugin @Inject private ClientThread clientThread; - @Inject - private TargetClickboxOverlay targetClickboxOverlay; - @Inject private TargetWeaknessOverlay targetWeaknessOverlay; - @Inject - private TargetMinimapOverlay targetMinimapOverlay; - @Inject private ChatMessageManager chatMessageManager; @@ -172,8 +174,15 @@ public class SlayerPlugin extends Plugin @Inject private ChatClient chatClient; + @Inject + private NpcIndicatorsService npcIndicatorsService; + @Getter(AccessLevel.PACKAGE) - private List highlightedTargets = new ArrayList<>(); + private final List targets = new ArrayList<>(); + + @Inject + @Named("developerMode") + boolean developerMode; private final Set taggedNpcs = new HashSet<>(); private int taggedNpcsDiedPrevTick; @@ -201,13 +210,16 @@ public class SlayerPlugin extends Plugin private boolean loginFlag; private final List targetNames = new ArrayList<>(); + public final Predicate isTarget = (n) -> config.highlightTargets() && targets.contains(n); + @Override protected void startUp() throws Exception { + chatCommandManager.registerCommandAsync(TASK_COMMAND_STRING, this::taskLookup, this::taskSubmit); + npcIndicatorsService.registerHighlighter(isTarget); + overlayManager.add(overlay); - overlayManager.add(targetClickboxOverlay); overlayManager.add(targetWeaknessOverlay); - overlayManager.add(targetMinimapOverlay); if (client.getGameState() == GameState.LOGGED_IN) { @@ -224,23 +236,21 @@ public class SlayerPlugin extends Plugin getStringProfileConfig(SlayerConfig.TASK_LOC_KEY), false)); } } - - chatCommandManager.registerCommandAsync(TASK_COMMAND_STRING, this::taskLookup, this::taskSubmit); } @Override protected void shutDown() throws Exception { + chatCommandManager.unregisterCommand(TASK_COMMAND_STRING); + npcIndicatorsService.unregisterHighlighter(isTarget); + npcIndicatorsService.rebuild(); + overlayManager.remove(overlay); - overlayManager.remove(targetClickboxOverlay); overlayManager.remove(targetWeaknessOverlay); - overlayManager.remove(targetMinimapOverlay); removeCounter(); - highlightedTargets.clear(); + targets.clear(); taggedNpcs.clear(); cachedXp = -1; - - chatCommandManager.unregisterCommand(TASK_COMMAND_STRING); } @Provides @@ -260,7 +270,7 @@ public class SlayerPlugin extends Plugin taskName = ""; amount = 0; loginFlag = true; - highlightedTargets.clear(); + targets.clear(); taggedNpcs.clear(); break; case LOGGED_IN: @@ -279,6 +289,16 @@ public class SlayerPlugin extends Plugin } } + @Subscribe + public void onCommandExecuted(CommandExecuted commandExecuted) + { + if (developerMode && commandExecuted.getCommand().equals("task")) + { + setTask(commandExecuted.getArguments()[0], 42, 42); + log.debug("Set task to {}", commandExecuted.getArguments()[0]); + } + } + @VisibleForTesting int getIntProfileConfig(String key) { @@ -313,13 +333,16 @@ public class SlayerPlugin extends Plugin setProfileConfig(SlayerConfig.TASK_LOC_KEY, taskLocation); } - @Subscribe + @Subscribe( + // Run prior to npc indicators plugin so targets is populated before the isTarget predicate is checked + priority = 1 + ) public void onNpcSpawned(NpcSpawned npcSpawned) { NPC npc = npcSpawned.getNpc(); if (isTarget(npc)) { - highlightedTargets.add(npc); + targets.add(npc); } } @@ -328,7 +351,7 @@ public class SlayerPlugin extends Plugin { NPC npc = npcDespawned.getNpc(); taggedNpcs.remove(npc); - highlightedTargets.remove(npc); + targets.remove(npc); } @Subscribe @@ -541,7 +564,7 @@ public class SlayerPlugin extends Plugin { Actor actor = hitsplatApplied.getActor(); Hitsplat hitsplat = hitsplatApplied.getHitsplat(); - if (hitsplat.getHitsplatType() == Hitsplat.HitsplatType.DAMAGE_ME && highlightedTargets.contains(actor)) + if (hitsplat.getHitsplatType() == Hitsplat.HitsplatType.DAMAGE_ME && targets.contains(actor)) { // If the actor is in highlightedTargets it must be an NPC and also a task assignment taggedNpcs.add((NPC) actor); @@ -562,18 +585,25 @@ public class SlayerPlugin extends Plugin @Subscribe private void onConfigChanged(ConfigChanged event) { - if (!event.getGroup().equals(SlayerConfig.GROUP_NAME) || !event.getKey().equals("infobox")) + if (!event.getGroup().equals(SlayerConfig.GROUP_NAME)) { return; } - if (config.showInfobox()) + if (event.getKey().equals("infobox")) { - clientThread.invoke(this::addCounter); + if (config.showInfobox()) + { + clientThread.invoke(this::addCounter); + } + else + { + removeCounter(); + } } else { - removeCounter(); + npcIndicatorsService.rebuild(); } } @@ -619,27 +649,25 @@ public class SlayerPlugin extends Plugin return false; } - String name = npc.getName(); - if (name == null) + final NPCComposition composition = npc.getTransformedComposition(); + if (composition == null) { return false; } - name = name.toLowerCase(); + final String name = composition.getName() + .replace('\u00A0', ' ') + .toLowerCase(); for (String target : targetNames) { if (name.contains(target)) { - NPCComposition composition = npc.getTransformedComposition(); - - if (composition != null) + if (ArrayUtils.contains(composition.getActions(), "Attack") + // Pick action is for zygomite-fungi + || ArrayUtils.contains(composition.getActions(), "Pick")) { - List actions = Arrays.asList(composition.getActions()); - if (actions.contains("Attack") || actions.contains("Pick")) //Pick action is for zygomite-fungi - { - return true; - } + return true; } } } @@ -662,13 +690,13 @@ public class SlayerPlugin extends Plugin private void rebuildTargetList() { - highlightedTargets.clear(); + targets.clear(); for (NPC npc : client.getNpcs()) { if (isTarget(npc)) { - highlightedTargets.add(npc); + targets.add(npc); } } } @@ -701,6 +729,7 @@ public class SlayerPlugin extends Plugin Task task = Task.getTask(name); rebuildTargetNames(task); rebuildTargetList(); + npcIndicatorsService.rebuild(); } private void addCounter() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetClickboxOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetClickboxOverlay.java deleted file mode 100644 index 441f1c6d85..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetClickboxOverlay.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2018, James Swindle - * Copyright (c) 2018, Adam - * Copyright (c) 2018, Shaun Dreclin - * 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.slayer; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.util.List; -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.util.ColorUtil; - -public class TargetClickboxOverlay extends Overlay -{ - private final SlayerConfig config; - private final SlayerPlugin plugin; - - @Inject - TargetClickboxOverlay(SlayerConfig config, SlayerPlugin plugin) - { - this.config = config; - this.plugin = plugin; - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!config.highlightTargets()) - { - return null; - } - - List targets = plugin.getHighlightedTargets(); - for (NPC target : targets) - { - renderTargetOverlay(graphics, target, config.getTargetColor()); - } - - return null; - } - - private void renderTargetOverlay(Graphics2D graphics, NPC actor, Color color) - { - Shape objectClickbox = actor.getConvexHull(); - if (objectClickbox != null) - { - graphics.setColor(color); - graphics.setStroke(new BasicStroke(2)); - graphics.draw(objectClickbox); - graphics.setColor(ColorUtil.colorWithAlpha(color, color.getAlpha() / 12)); - graphics.fill(objectClickbox); - } - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetMinimapOverlay.java deleted file mode 100644 index ea12fde38a..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetMinimapOverlay.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2018, James Swindle - * Copyright (c) 2018, Adam - * Copyright (c) 2018, Shaun Dreclin - * 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.slayer; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.util.List; -import javax.inject.Inject; -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; - -public class TargetMinimapOverlay extends Overlay -{ - private final SlayerConfig config; - private final SlayerPlugin plugin; - - @Inject - TargetMinimapOverlay(SlayerConfig config, SlayerPlugin plugin) - { - this.config = config; - this.plugin = plugin; - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_WIDGETS); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!config.highlightTargets()) - { - return null; - } - - List targets = plugin.getHighlightedTargets(); - for (NPC target : targets) - { - renderTargetOverlay(graphics, target, config.getTargetColor()); - } - - return null; - } - - private void renderTargetOverlay(Graphics2D graphics, NPC actor, Color color) - { - Point minimapLocation = actor.getMinimapLocation(); - if (minimapLocation != null) - { - OverlayUtil.renderMinimapLocation(graphics, minimapLocation, color); - } - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java index 91f331d06b..cc20cab485 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java @@ -64,7 +64,7 @@ class TargetWeaknessOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - final List targets = plugin.getHighlightedTargets(); + final List targets = plugin.getTargets(); if (targets.isEmpty() || !config.weaknessPrompt()) { diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java index 02b679e496..50692a915a 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/PluginManagerTest.java @@ -28,7 +28,6 @@ import com.google.common.reflect.ClassPath; import com.google.common.reflect.ClassPath.ClassInfo; import com.google.inject.Guice; import com.google.inject.Injector; -import com.google.inject.Module; import com.google.inject.grapher.graphviz.GraphvizGrapher; import com.google.inject.grapher.graphviz.GraphvizModule; import com.google.inject.testing.fieldbinder.Bind; @@ -39,10 +38,8 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Objects; import java.util.Set; import net.runelite.api.Client; @@ -153,24 +150,28 @@ public class PluginManagerTest @Test public void dumpGraph() throws Exception { - List modules = new ArrayList<>(); - modules.add(new GraphvizModule()); - modules.add(new RuneLiteModule(mock(OkHttpClient.class), () -> null, true, false, - RuneLite.DEFAULT_SESSION_FILE, - RuneLite.DEFAULT_CONFIG_FILE)); - PluginManager pluginManager = new PluginManager(true, false, null, null, null, null); pluginManager.loadCorePlugins(); - modules.addAll(pluginManager.getPlugins()); - File file = folder.newFile(); - try (PrintWriter out = new PrintWriter(file, "UTF-8")) + Injector graphvizInjector = Guice.createInjector(new GraphvizModule()); + GraphvizGrapher graphvizGrapher = graphvizInjector.getInstance(GraphvizGrapher.class); + + File dotFolder = folder.newFolder(); + try (PrintWriter out = new PrintWriter(new File(dotFolder, "runelite.dot"), "UTF-8")) { - Injector injector = Guice.createInjector(modules); - GraphvizGrapher grapher = injector.getInstance(GraphvizGrapher.class); - grapher.setOut(out); - grapher.setRankdir("TB"); - grapher.graph(injector); + graphvizGrapher.setOut(out); + graphvizGrapher.setRankdir("TB"); + graphvizGrapher.graph(RuneLite.getInjector()); + } + + for (Plugin p : pluginManager.getPlugins()) + { + try (PrintWriter out = new PrintWriter(new File(dotFolder, p.getName() + ".dot"), "UTF-8")) + { + graphvizGrapher.setOut(out); + graphvizGrapher.setRankdir("TB"); + graphvizGrapher.graph(p.getInjector()); + } } } 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 cb81a836d2..9ccbcf3423 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 @@ -99,7 +99,7 @@ public class NpcIndicatorsPluginTest when(npcIndicatorsConfig.getNpcToHighlight()).thenReturn("goblin"); when(npcIndicatorsConfig.deadNpcMenuColor()).thenReturn(Color.RED); - npcIndicatorsPlugin.rebuildAllNpcs(); + npcIndicatorsPlugin.rebuild(); NPC npc = mock(NPC.class); when(npc.getName()).thenReturn("Goblin"); @@ -124,7 +124,7 @@ public class NpcIndicatorsPluginTest when(npcIndicatorsConfig.highlightMenuNames()).thenReturn(true); when(npcIndicatorsConfig.getHighlightColor()).thenReturn(Color.BLUE); - npcIndicatorsPlugin.rebuildAllNpcs(); + npcIndicatorsPlugin.rebuild(); NPC npc = mock(NPC.class); when(npc.getName()).thenReturn("Goblin"); @@ -146,7 +146,7 @@ public class NpcIndicatorsPluginTest { when(npcIndicatorsConfig.getNpcToHighlight()).thenReturn("Joseph"); - npcIndicatorsPlugin.rebuildAllNpcs(); + npcIndicatorsPlugin.rebuild(); NPC npc = mock(NPC.class); when(npc.getName()).thenReturn("Joseph"); @@ -165,7 +165,7 @@ public class NpcIndicatorsPluginTest { when(npcIndicatorsConfig.getNpcToHighlight()).thenReturn("Werewolf"); - npcIndicatorsPlugin.rebuildAllNpcs(); + npcIndicatorsPlugin.rebuild(); NPC npc = mock(NPC.class); when(npc.getName()).thenReturn("Joseph"); 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 6785721349..d28aefd7c2 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 @@ -31,6 +31,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.concurrent.ScheduledExecutorService; import javax.inject.Inject; +import javax.inject.Named; import net.runelite.api.ChatMessageType; import static net.runelite.api.ChatMessageType.GAMEMESSAGE; import net.runelite.api.Client; @@ -55,6 +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.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.http.api.chat.ChatClient; @@ -168,6 +170,14 @@ public class SlayerPluginTest @Bind ChatClient chatClient; + @Bind + @Named("developerMode") + boolean developerMode; + + @Mock + @Bind + NpcIndicatorsService npcIndicatorsService; + @Inject SlayerPlugin slayerPlugin; @@ -871,14 +881,13 @@ public class SlayerPluginTest slayerPlugin.onStatChanged(statChanged); NPCComposition npcComposition = mock(NPCComposition.class); + when(npcComposition.getName()).thenReturn("Suqah"); when(npcComposition.getActions()).thenReturn(new String[]{"Attack"}); NPC npc1 = mock(NPC.class); - when(npc1.getName()).thenReturn("Suqah"); when(npc1.getTransformedComposition()).thenReturn(npcComposition); NPC npc2 = mock(NPC.class); - when(npc2.getName()).thenReturn("Suqah"); when(npc2.getTransformedComposition()).thenReturn(npcComposition); when(client.getNpcs()).thenReturn(Arrays.asList(npc1, npc2)); From c68bf31f6b8286e541cd3718121fb251b078248c Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 7 Aug 2021 23:44:26 -0400 Subject: [PATCH 6/9] redis pool: don't reuse broken jedis instances --- .../http/service/util/redis/RedisPool.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java b/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java index a69232ed55..c0d4a65a29 100644 --- a/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java +++ b/http-service/src/main/java/net/runelite/http/service/util/redis/RedisPool.java @@ -27,17 +27,22 @@ package net.runelite.http.service.util.redis; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; @Component +@Slf4j public class RedisPool { + private final String redisHost; private final BlockingQueue queue; RedisPool(@Value("${redis.pool.size:10}") int queueSize, @Value("${redis.host:localhost}") String redisHost) { + this.redisHost = redisHost; + queue = new ArrayBlockingQueue<>(queueSize); for (int i = 0; i < queueSize; ++i) { @@ -74,7 +79,24 @@ public class RedisPool @Override public void close() { - queue.offer(this); + if (!getClient().isBroken()) + { + queue.offer(this); + return; + } + + log.warn("jedis client is broken, creating new client"); + + try + { + super.close(); + } + catch (Exception e) + { + log.warn("unable to close broken jedis", e); + } + + queue.offer(new PooledJedis(redisHost)); } } } From a8e745ac62760da88caacbbdcfd3d7f77a82d1a4 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 8 Aug 2021 13:45:36 -0400 Subject: [PATCH 7/9] interact highlight: set overlay priority to high This is to place it above npc indicators --- .../plugins/interacthighlight/InteractHighlightOverlay.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/interacthighlight/InteractHighlightOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/interacthighlight/InteractHighlightOverlay.java index 664d274f5a..a5dd9c95da 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/interacthighlight/InteractHighlightOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/interacthighlight/InteractHighlightOverlay.java @@ -59,7 +59,7 @@ class InteractHighlightOverlay extends Overlay this.modelOutlineRenderer = modelOutlineRenderer; setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_SCENE); - setPriority(OverlayPriority.LOW); + setPriority(OverlayPriority.HIGH); } @Override From 795c0e4a07259323c80aefcb9d9a614070d792de Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 8 Aug 2021 21:09:49 -0400 Subject: [PATCH 8/9] widget overlay: rebuild overlay layers when xp tracker moves The overlay layers are sorted by position and then by priority, so changing the position without rebuilding them is incorrect. --- .../main/java/net/runelite/client/RuneLite.java | 2 +- .../client/ui/overlay/WidgetOverlay.java | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index 41c7fc8de3..dde04da268 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -324,7 +324,7 @@ public class RuneLite if (!isOutdated) { // Add core overlays - WidgetOverlay.createOverlays(client).forEach(overlayManager::add); + WidgetOverlay.createOverlays(overlayManager, client).forEach(overlayManager::add); overlayManager.add(worldMapOverlay.get()); eventBus.register(worldMapOverlay.get()); overlayManager.add(tooltipOverlay.get()); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java index 384acab9d8..fbc95e3f77 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java @@ -39,13 +39,13 @@ import net.runelite.api.widgets.WidgetInfo; @Slf4j public class WidgetOverlay extends Overlay { - public static Collection createOverlays(final Client client) + public static Collection createOverlays(final OverlayManager overlayManager, final Client client) { return Arrays.asList( new WidgetOverlay(client, WidgetInfo.RESIZABLE_MINIMAP_WIDGET, OverlayPosition.CANVAS_TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.RESIZABLE_MINIMAP_STONES_WIDGET, OverlayPosition.CANVAS_TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.FOSSIL_ISLAND_OXYGENBAR, OverlayPosition.TOP_CENTER), - new XpTrackerWidgetOverlay(client, WidgetInfo.EXPERIENCE_TRACKER_WIDGET, OverlayPosition.TOP_RIGHT), + new XpTrackerWidgetOverlay(overlayManager, client, WidgetInfo.EXPERIENCE_TRACKER_WIDGET, OverlayPosition.TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.RAIDS_POINTS_INFOBOX, OverlayPosition.TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.TOB_PARTY_INTERFACE, OverlayPosition.TOP_LEFT), new WidgetOverlay(client, WidgetInfo.TOB_PARTY_STATS, OverlayPosition.TOP_LEFT), @@ -190,9 +190,12 @@ public class WidgetOverlay extends Overlay private static class XpTrackerWidgetOverlay extends WidgetOverlay { - private XpTrackerWidgetOverlay(Client client, WidgetInfo widgetInfo, OverlayPosition overlayPosition) + private final OverlayManager overlayManager; + + private XpTrackerWidgetOverlay(OverlayManager overlayManager, Client client, WidgetInfo widgetInfo, OverlayPosition overlayPosition) { super(client, widgetInfo, overlayPosition); + this.overlayManager = overlayManager; } /** @@ -224,7 +227,13 @@ public class WidgetOverlay extends Overlay position = OverlayPosition.TOP_LEFT; break; } - setPosition(position); + + if (position != super.getPosition()) + { + log.debug("Xp tracker moved position"); + setPosition(position); + overlayManager.rebuildOverlayLayers(); + } return position; } } From a5956739740204314c83f0690eeeb809dd222113 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 8 Aug 2021 21:09:52 -0400 Subject: [PATCH 9/9] widget overlay: lower priority of oxygen and hp interfaces The client attempts to force these to always be below the xp tracker, and having them at an equal priority can cause our overlay renderer to fight it by laying out them above the xp tracker --- .../runelite/client/ui/overlay/WidgetOverlay.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java index fbc95e3f77..67d20cf8bd 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java @@ -44,7 +44,8 @@ public class WidgetOverlay extends Overlay return Arrays.asList( new WidgetOverlay(client, WidgetInfo.RESIZABLE_MINIMAP_WIDGET, OverlayPosition.CANVAS_TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.RESIZABLE_MINIMAP_STONES_WIDGET, OverlayPosition.CANVAS_TOP_RIGHT), - new WidgetOverlay(client, WidgetInfo.FOSSIL_ISLAND_OXYGENBAR, OverlayPosition.TOP_CENTER), + // The client forces the oxygen bar below the xp tracker, so set its priority lower + new WidgetOverlay(client, WidgetInfo.FOSSIL_ISLAND_OXYGENBAR, OverlayPosition.TOP_CENTER, OverlayPriority.HIGH), new XpTrackerWidgetOverlay(overlayManager, client, WidgetInfo.EXPERIENCE_TRACKER_WIDGET, OverlayPosition.TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.RAIDS_POINTS_INFOBOX, OverlayPosition.TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.TOB_PARTY_INTERFACE, OverlayPosition.TOP_LEFT), @@ -63,7 +64,8 @@ public class WidgetOverlay extends Overlay new WidgetOverlay(client, WidgetInfo.LMS_KDA, OverlayPosition.TOP_RIGHT), new WidgetOverlay(client, WidgetInfo.GAUNTLET_TIMER_CONTAINER, OverlayPosition.TOP_LEFT), new WidgetOverlay(client, WidgetInfo.HALLOWED_SEPULCHRE_TIMER_CONTAINER, OverlayPosition.TOP_LEFT), - new WidgetOverlay(client, WidgetInfo.HEALTH_OVERLAY_BAR, OverlayPosition.TOP_CENTER), + // The client forces the health overlay bar below the xp tracker, so set its priority lower + new WidgetOverlay(client, WidgetInfo.HEALTH_OVERLAY_BAR, OverlayPosition.TOP_CENTER, OverlayPriority.HIGH), new WidgetOverlay(client, WidgetInfo.TOB_HEALTH_BAR, OverlayPosition.TOP_CENTER), new WidgetOverlay(client, WidgetInfo.NIGHTMARE_PILLAR_HEALTH, OverlayPosition.TOP_LEFT), new WidgetOverlay(client, WidgetInfo.VOLCANIC_MINE_VENTS_INFOBOX_GROUP, OverlayPosition.BOTTOM_RIGHT), @@ -84,10 +86,15 @@ public class WidgetOverlay extends Overlay private boolean revalidate; private WidgetOverlay(final Client client, final WidgetInfo widgetInfo, final OverlayPosition overlayPosition) + { + this(client, widgetInfo, overlayPosition, OverlayPriority.HIGHEST); + } + + private WidgetOverlay(final Client client, final WidgetInfo widgetInfo, final OverlayPosition overlayPosition, final OverlayPriority overlayPriority) { this.client = client; this.widgetInfo = widgetInfo; - setPriority(OverlayPriority.HIGHEST); + setPriority(overlayPriority); setLayer(OverlayLayer.UNDER_WIDGETS); setPosition(overlayPosition); // It's almost possible to drawAfterInterface(widgetInfo.getGroupId()) here, but that fires