From c48d8db3a18ce14265eb6cba50304e666531580e Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Tue, 11 Feb 2020 13:39:01 -0800 Subject: [PATCH 01/25] clues: Create NamedObjectClueScroll interface This commit adds a new clue type, NamedObjectClueScroll, which allows highlighting of objects based on object name. (and optionally region ID(s) where that object should reside) This commit introduces two new fidlds to the ClueScrollPlugin class to track player plane changes to address some unusual client behavior. Namely, when a player travels up or down planes, multiloc objects only have their varbit values updated on the tick after the plane change occurs. Since these objects must be in their desired state before checking their name, these fields are used to track both the player's plane, and whether the plugin should wait an extra tick to process the new plane's objects based on a plane change occurring. --- .../plugins/cluescrolls/ClueScrollPlugin.java | 219 +++++++++++++++++- .../clues/NamedObjectClueScroll.java | 41 ++++ 2 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/NamedObjectClueScroll.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java index 08b5bb46c4..6087d683ee 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java @@ -37,9 +37,13 @@ import java.awt.geom.Area; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.stream.Stream; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Named; import joptsimple.internal.Strings; @@ -65,12 +69,24 @@ import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.CommandExecuted; +import net.runelite.api.events.DecorativeObjectChanged; +import net.runelite.api.events.DecorativeObjectDespawned; +import net.runelite.api.events.DecorativeObjectSpawned; +import net.runelite.api.events.GameObjectChanged; +import net.runelite.api.events.GameObjectDespawned; +import net.runelite.api.events.GameObjectSpawned; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; +import net.runelite.api.events.GroundObjectChanged; +import net.runelite.api.events.GroundObjectDespawned; +import net.runelite.api.events.GroundObjectSpawned; import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcSpawned; +import net.runelite.api.events.WallObjectChanged; +import net.runelite.api.events.WallObjectDespawned; +import net.runelite.api.events.WallObjectSpawned; import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetID; @@ -96,6 +112,7 @@ import net.runelite.client.plugins.cluescrolls.clues.LocationClueScroll; import net.runelite.client.plugins.cluescrolls.clues.LocationsClueScroll; import net.runelite.client.plugins.cluescrolls.clues.MapClue; import net.runelite.client.plugins.cluescrolls.clues.MusicClue; +import net.runelite.client.plugins.cluescrolls.clues.NamedObjectClueScroll; import net.runelite.client.plugins.cluescrolls.clues.NpcClueScroll; import net.runelite.client.plugins.cluescrolls.clues.ObjectClueScroll; import net.runelite.client.plugins.cluescrolls.clues.SkillChallengeClue; @@ -108,6 +125,7 @@ import net.runelite.client.ui.overlay.components.TextComponent; import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; +import org.apache.commons.lang3.ArrayUtils; @PluginDescriptor( name = "Clue Scroll", @@ -137,6 +155,9 @@ public class ClueScrollPlugin extends Plugin @Getter private final List objectsToMark = new ArrayList<>(); + @Getter + private final Set namedObjectsToMark = new HashSet<>(); + @Getter private Item[] equippedItems; @@ -180,6 +201,12 @@ public class ClueScrollPlugin extends Plugin private Integer clueItemId; private boolean worldMapPointsSet = false; + // Some objects will only update to their "active" state when changing to their plane after varbit changes, + // which take one extra tick to fire after the plane change. These fields are used to track those changes and delay + // scans of the current plane's tiles accordingly. + private int currentPlane = -1; + private boolean namedObjectCheckThisTick; + private final TextComponent textComponent = new TextComponent(); @Provides @@ -211,8 +238,11 @@ public class ClueScrollPlugin extends Plugin overlayManager.remove(clueScrollWorldOverlay); overlayManager.remove(clueScrollMusicOverlay); npcsToMark.clear(); + namedObjectsToMark.clear(); inventoryItems = null; equippedItems = null; + currentPlane = -1; + namedObjectCheckThisTick = false; resetClue(true); } @@ -344,6 +374,94 @@ public class ClueScrollPlugin extends Plugin } } + @Subscribe + public void onDecorativeObjectChanged(final DecorativeObjectChanged event) + { + tileObjectChangedHandler(event.getPrevious(), event.getDecorativeObject()); + } + + @Subscribe + public void onDecorativeObjectDespawned(final DecorativeObjectDespawned event) + { + tileObjectDespawnedHandler(event.getDecorativeObject()); + } + + @Subscribe + public void onDecorativeObjectSpawned(final DecorativeObjectSpawned event) + { + tileObjectSpawnedHandler(event.getDecorativeObject()); + } + + @Subscribe + public void onGameObjectChanged(final GameObjectChanged event) + { + tileObjectChangedHandler(event.getPrevious(), event.getGameObject()); + } + + @Subscribe + public void onGameObjectDespawned(final GameObjectDespawned event) + { + tileObjectDespawnedHandler(event.getGameObject()); + } + + @Subscribe + public void onGameObjectSpawned(final GameObjectSpawned event) + { + tileObjectSpawnedHandler(event.getGameObject()); + } + + @Subscribe + public void onGroundObjectChanged(final GroundObjectChanged event) + { + tileObjectChangedHandler(event.getPrevious(), event.getGroundObject()); + } + + @Subscribe + public void onGroundObjectDespawned(final GroundObjectDespawned event) + { + tileObjectDespawnedHandler(event.getGroundObject()); + } + + @Subscribe + public void onGroundObjectSpawned(final GroundObjectSpawned event) + { + tileObjectSpawnedHandler(event.getGroundObject()); + } + + @Subscribe + public void onWallObjectChanged(final WallObjectChanged event) + { + tileObjectChangedHandler(event.getPrevious(), event.getWallObject()); + } + + @Subscribe + public void onWallObjectDespawned(final WallObjectDespawned event) + { + tileObjectDespawnedHandler(event.getWallObject()); + } + + @Subscribe + public void onWallObjectSpawned(final WallObjectSpawned event) + { + tileObjectSpawnedHandler(event.getWallObject()); + } + + private void tileObjectChangedHandler(final TileObject prev, final TileObject changedTo) + { + tileObjectDespawnedHandler(prev); + tileObjectSpawnedHandler(changedTo); + } + + private void tileObjectDespawnedHandler(final TileObject despawned) + { + namedObjectsToMark.remove(despawned); + } + + private void tileObjectSpawnedHandler(final TileObject spawned) + { + checkClueNamedObject(clue, spawned); + } + @Subscribe public void onConfigChanged(ConfigChanged event) { @@ -356,7 +474,14 @@ public class ClueScrollPlugin extends Plugin @Subscribe public void onGameStateChanged(final GameStateChanged event) { - if (event.getGameState() == GameState.LOGIN_SCREEN) + final GameState state = event.getGameState(); + + if (state != GameState.LOGGED_IN) + { + namedObjectsToMark.clear(); + } + + if (state == GameState.LOGIN_SCREEN) { resetClue(true); } @@ -425,6 +550,20 @@ public class ClueScrollPlugin extends Plugin } } + // Load the current plane's tiles if a tick has elapsed since the player has changed planes + if (namedObjectCheckThisTick) + { + namedObjectCheckThisTick = false; + checkClueNamedObjects(clue); + } + + // Delay one tick when changing planes before scanning for new named objects on the new plane + if (currentPlane != client.getPlane()) + { + currentPlane = client.getPlane(); + namedObjectCheckThisTick = true; + } + // Reset clue when receiving a new beginner or master clue // These clues use a single item ID, so we cannot detect step changes based on the item ID changing final Widget chatDialogClueItem = client.getWidget(WidgetInfo.DIALOG_SPRITE_SPRITE); @@ -525,6 +664,7 @@ public class ClueScrollPlugin extends Plugin worldMapPointManager.removeIf(ClueScrollWorldMapPoint.class::isInstance); worldMapPointsSet = false; npcsToMark.clear(); + namedObjectsToMark.clear(); if (config.displayHintArrows()) { @@ -713,7 +853,6 @@ public class ClueScrollPlugin extends Plugin final Scene scene = client.getScene(); final Tile[][][] tiles = scene.getTiles(); final Tile tile = tiles[client.getPlane()][localLocation.getSceneX()][localLocation.getSceneY()]; - objectsToMark.clear(); for (GameObject object : tile.getGameObjects()) { @@ -781,6 +920,81 @@ public class ClueScrollPlugin extends Plugin } } + /** + * Scans all of the current plane's loaded tiles for {@link TileObject}s and passes any found objects to + * {@link ClueScrollPlugin#checkClueNamedObject(ClueScroll, TileObject)} for storing in the cache of discovered + * named objects. + * + * @param clue The active clue scroll + */ + private void checkClueNamedObjects(@Nullable ClueScroll clue) + { + if (!(clue instanceof NamedObjectClueScroll)) + { + return; + } + + // Search loaded tiles for objects + for (final Tile[] tiles : client.getScene().getTiles()[client.getPlane()]) + { + for (final Tile tile : tiles) + { + if (tile == null) + { + continue; + } + + for (final GameObject object : tile.getGameObjects()) + { + if (object == null) + { + continue; + } + + checkClueNamedObject(clue, object); + } + } + } + } + + /** + * Checks passed objects against the active clue's object names and regions. If the clue is a + * {@link NamedObjectClueScroll} and the object matches its allowable object names and is within its regions, the + * object will be stored in the cache of discovered named objects. + * + * @param clue The active clue scroll + * @param object The spawned or scanned object + */ + private void checkClueNamedObject(@Nullable final ClueScroll clue, @Nonnull final TileObject object) + { + if (!(clue instanceof NamedObjectClueScroll)) + { + return; + } + + final NamedObjectClueScroll namedObjectClue = (NamedObjectClueScroll) clue; + + final String[] objectNames = namedObjectClue.getObjectNames(); + final int[] regionIds = namedObjectClue.getObjectRegions(); + + if (objectNames == null || objectNames.length == 0 + || regionIds != null && !ArrayUtils.contains(regionIds, object.getWorldLocation().getRegionID())) + { + return; + } + + final ObjectComposition comp = client.getObjectDefinition(object.getId()); + final ObjectComposition impostor = comp.getImpostorIds() != null ? comp.getImpostor() : comp; + + for (final String name : objectNames) + { + if (comp.getName().equals(name) || impostor.getName().equals(name)) + { + namedObjectsToMark.add(object); + } + } + } + private void updateClue(final ClueScroll clue) { if (clue == null || clue == this.clue) @@ -790,6 +1004,7 @@ public class ClueScrollPlugin extends Plugin resetClue(false); checkClueNPCs(clue, client.getCachedNPCs()); + checkClueNamedObjects(clue); // If we have a clue, save that knowledge // so the clue window doesn't have to be open. this.clue = clue; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/NamedObjectClueScroll.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/NamedObjectClueScroll.java new file mode 100644 index 0000000000..1b52b1c213 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/NamedObjectClueScroll.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import javax.annotation.Nullable; + +/** + * Represents a clue which should highlight objects of a given name rather than a specific ID and location, as some + * clues will call for a general action which can be completed at any number of locations. The area in which this + * highlighting should occur can be restricted by giving a non-null array of region IDs where only objects within those + * regions will be highlighted. + */ +public interface NamedObjectClueScroll +{ + String[] getObjectNames(); + + @Nullable + int[] getObjectRegions(); +} From c2785628348effda93d675cb89e6d059fc163de2 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Tue, 11 Feb 2020 13:40:12 -0800 Subject: [PATCH 02/25] SkillChallengeClue: Highlight broken Dorgesh-kaan lamps For the skill challenge clue "Fix a magical lamp in Dorgesh-Kaan.", highlight lamps in the area which are broken. Fixes runelite/runelite#10069 Closes runelite/runelite#10117 --- .../cluescrolls/clues/SkillChallengeClue.java | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java index be50cbd31c..596d2ae821 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java @@ -32,7 +32,12 @@ import net.runelite.api.EquipmentInventorySlot; import net.runelite.api.Item; import net.runelite.api.ItemID; import net.runelite.api.NPC; +import net.runelite.api.Point; +import net.runelite.api.TileObject; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_BORDER_COLOR; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_FILL_COLOR; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_HOVER_BORDER_COLOR; import net.runelite.client.plugins.cluescrolls.clues.item.AnyRequirementCollection; import static net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirements.*; import net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirement; @@ -50,7 +55,7 @@ import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_C import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; @Getter -public class SkillChallengeClue extends ClueScroll implements NpcClueScroll +public class SkillChallengeClue extends ClueScroll implements NpcClueScroll, NamedObjectClueScroll { @AllArgsConstructor @Getter @@ -138,7 +143,7 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll new SkillChallengeClue("Smith a mithril 2h sword.", item(ItemID.HAMMER), xOfItem(ItemID.MITHRIL_BAR, 3)), new SkillChallengeClue("Catch a raw shark.", ANY_HARPOON), new SkillChallengeClue("Cut a yew log.", ANY_AXE), - new SkillChallengeClue("Fix a magical lamp in Dorgesh-Kaan.", item(ItemID.LIGHT_ORB)), + new SkillChallengeClue("Fix a magical lamp in Dorgesh-Kaan.", new String[] { "Broken lamp" }, new int[] { 10834, 10835 }, item(ItemID.LIGHT_ORB)), new SkillChallengeClue("Burn a yew log.", item(ItemID.YEW_LOGS), item(ItemID.TINDERBOX)), new SkillChallengeClue("Cook a swordfish", "cook a swordfish", item(ItemID.RAW_SWORDFISH)), new SkillChallengeClue("Craft multiple cosmic runes from a single essence.", item(ItemID.PURE_ESSENCE)), @@ -187,6 +192,8 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll private final ItemRequirement[] itemRequirements; private final SingleItemRequirement returnItem; private final boolean requireEquip; + private final String[] objectNames; + private final int[] objectRegions; @Setter private boolean challengeCompleted; @@ -201,6 +208,8 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll this.returnItem = returnItem; this.challengeCompleted = false; this.requireEquip = false; + this.objectNames = new String[0]; + this.objectRegions = null; } // Non-cryptic Sherlock Tasks @@ -209,20 +218,32 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll this(challenge, challenge.toLowerCase(), itemRequirements); } + // Non-cryptic Sherlock Tasks + private SkillChallengeClue(String challenge, String[] objectNames, int[] objectRegions, ItemRequirement ... itemRequirements) + { + this(challenge, challenge.toLowerCase(), false, objectNames, objectRegions, itemRequirements); + } + // Non-cryptic Sherlock Tasks private SkillChallengeClue(String challenge, boolean requireEquip, ItemRequirement ... itemRequirements) { - this(challenge, challenge.toLowerCase(), requireEquip, itemRequirements); + this(challenge, challenge.toLowerCase(), requireEquip, new String[0], null, itemRequirements); } // Sherlock Tasks private SkillChallengeClue(String challenge, String rawChallenge, ItemRequirement ... itemRequirements) { - this(challenge, rawChallenge, false, itemRequirements); + this(challenge, rawChallenge, false, new String[0], null, itemRequirements); } // Sherlock Tasks private SkillChallengeClue(String challenge, String rawChallenge, boolean requireEquip, ItemRequirement ... itemRequirements) + { + this(challenge, rawChallenge, requireEquip, new String[0], null, itemRequirements); + } + + // Sherlock Tasks + private SkillChallengeClue(String challenge, String rawChallenge, boolean requireEquip, String[] objectNames, int[] objectRegions, ItemRequirement ... itemRequirements) { this.type = ChallengeType.SHERLOCK; this.challenge = challenge; @@ -230,6 +251,8 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll this.itemRequirements = itemRequirements; this.challengeCompleted = false; this.requireEquip = requireEquip; + this.objectNames = objectNames; + this.objectRegions = objectRegions; this.returnText = "" + rawChallenge + ""; this.returnItem = null; @@ -294,6 +317,25 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); } } + + // Mark objects + if (!challengeCompleted && objectNames.length > 0 && plugin.getNamedObjectsToMark() != null) + { + final Point mousePosition = plugin.getClient().getMouseCanvasPosition(); + + for (final TileObject object : plugin.getNamedObjectsToMark()) + { + if (plugin.getClient().getPlane() != object.getPlane()) + { + continue; + } + + OverlayUtil.renderHoverableArea(graphics, object.getClickbox(), mousePosition, + CLICKBOX_FILL_COLOR, CLICKBOX_BORDER_COLOR, CLICKBOX_HOVER_BORDER_COLOR); + + OverlayUtil.renderImageLocation(plugin.getClient(), graphics, object.getLocalLocation(), plugin.getClueScrollImage(), IMAGE_Z_OFFSET); + } + } } private static List getRequirements(ClueScrollPlugin plugin, boolean requireEquipped, ItemRequirement ... requirements) From ba30018b1bd75bbae6a657340b57ca79e30070f8 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Sun, 8 Mar 2020 22:31:10 +0100 Subject: [PATCH 03/25] Add support for component tooltips Signed-off-by: Tomas Slusny --- .../overlay/components/TooltipComponent.java | 21 +++++++++++++++++-- .../client/ui/overlay/tooltip/Tooltip.java | 16 +++++++++++--- .../ui/overlay/tooltip/TooltipOverlay.java | 21 ++++++++++++++----- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java index 2e4b943063..fee7332497 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java @@ -34,10 +34,9 @@ import java.awt.Rectangle; import java.util.regex.Pattern; import lombok.Setter; import net.runelite.api.IndexedSprite; -import net.runelite.client.ui.overlay.RenderableEntity; @Setter -public class TooltipComponent implements RenderableEntity +public class TooltipComponent implements LayoutableRenderableEntity { private static final Pattern BR = Pattern.compile("
"); private static final int OFFSET = 4; @@ -225,4 +224,22 @@ public class TooltipComponent implements RenderableEntity } } } + + @Override + public Rectangle getBounds() + { + return null; + } + + @Override + public void setPreferredLocation(Point position) + { + this.position = position; + } + + @Override + public void setPreferredSize(Dimension dimension) + { + + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/Tooltip.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/Tooltip.java index f0c3700850..50974ada31 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/Tooltip.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/Tooltip.java @@ -24,12 +24,22 @@ */ package net.runelite.client.ui.overlay.tooltip; -import lombok.AllArgsConstructor; import lombok.Data; +import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity; @Data -@AllArgsConstructor public class Tooltip { - private final String text; + private String text; + private LayoutableRenderableEntity component; + + public Tooltip(final String text) + { + this.text = text; + } + + public Tooltip(final LayoutableRenderableEntity component) + { + this.component = component; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java index 314adffee0..f808fa49f2 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java @@ -38,6 +38,7 @@ 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.OverlayPriority; +import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity; import net.runelite.client.ui.overlay.components.TooltipComponent; @Singleton @@ -97,12 +98,22 @@ public class TooltipOverlay extends Overlay for (Tooltip tooltip : tooltips) { - final TooltipComponent tooltipComponent = new TooltipComponent(); - tooltipComponent.setModIcons(client.getModIcons()); - tooltipComponent.setText(tooltip.getText()); - tooltipComponent.setPosition(new Point(tooltipX, tooltipY + newBounds.height)); + final LayoutableRenderableEntity entity; - final Dimension dimension = tooltipComponent.render(graphics); + if (tooltip.getComponent() != null) + { + entity = tooltip.getComponent(); + } + else + { + final TooltipComponent tooltipComponent = new TooltipComponent(); + tooltipComponent.setModIcons(client.getModIcons()); + tooltipComponent.setText(tooltip.getText()); + entity = tooltipComponent; + } + + entity.setPreferredLocation(new Point(tooltipX, tooltipY + newBounds.height)); + final Dimension dimension = entity.render(graphics); // Create incremental tooltip newBounds newBounds.height += dimension.height + PADDING; From 982b1749ce28e128ebebf2c1719da30b3434f75a Mon Sep 17 00:00:00 2001 From: dekvall Date: Thu, 27 Feb 2020 01:55:18 +0100 Subject: [PATCH 04/25] ground items: add support for quantity thresholds Adds the ability to use `<` and `>` when configuring highlighted or hidden drops. --- .../grounditems/GroundItemsOverlay.java | 4 +- .../grounditems/GroundItemsPlugin.java | 18 ++--- .../plugins/grounditems/ItemThreshold.java | 80 +++++++++++++++++++ .../plugins/grounditems/NamedQuantity.java | 41 ++++++++++ .../grounditems/WildcardMatchLoader.java | 24 +++--- .../grounditems/WildcardMatchLoaderTest.java | 27 +++++-- 6 files changed, 166 insertions(+), 28 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/grounditems/ItemThreshold.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/grounditems/NamedQuantity.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index 0624652fb7..67b4cb8467 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -188,8 +188,8 @@ public class GroundItemsOverlay extends Overlay continue; } - final Color highlighted = plugin.getHighlighted(item.getName(), item.getGePrice(), item.getHaPrice()); - final Color hidden = plugin.getHidden(item.getName(), item.getGePrice(), item.getHaPrice(), item.isTradeable()); + final Color highlighted = plugin.getHighlighted(new NamedQuantity(item), item.getGePrice(), item.getHaPrice()); + final Color hidden = plugin.getHidden(new NamedQuantity(item), item.getGePrice(), item.getHaPrice(), item.isTradeable()); if (highlighted == null && !plugin.isHotKeyPressed()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java index cf278ac654..8691cae1d3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java @@ -61,7 +61,6 @@ import net.runelite.api.Tile; import net.runelite.api.TileItem; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ClientTick; -import net.runelite.client.events.ConfigChanged; import net.runelite.api.events.FocusChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.ItemDespawned; @@ -72,6 +71,7 @@ import net.runelite.api.events.MenuOptionClicked; 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.events.NpcLootReceived; import net.runelite.client.events.PlayerLootReceived; import net.runelite.client.game.ItemManager; @@ -164,8 +164,8 @@ public class GroundItemsPlugin extends Plugin @Getter private final Map collectedGroundItems = new LinkedHashMap<>(); private final Map priceChecks = new LinkedHashMap<>(); - private LoadingCache highlightedItems; - private LoadingCache hiddenItems; + private LoadingCache highlightedItems; + private LoadingCache hiddenItems; private final Queue droppedItemQueue = EvictingQueue.create(16); // recently dropped items @Provides @@ -233,7 +233,7 @@ public class GroundItemsPlugin extends Plugin } boolean shouldNotify = !config.onlyShowLoot() && config.highlightedColor().equals(getHighlighted( - groundItem.getName(), + new NamedQuantity(groundItem), groundItem.getGePrice(), groundItem.getHaPrice())); @@ -361,7 +361,7 @@ public class GroundItemsPlugin extends Plugin groundItem.setLootType(lootType); boolean shouldNotify = config.onlyShowLoot() && config.highlightedColor().equals(getHighlighted( - groundItem.getName(), + new NamedQuantity(groundItem), groundItem.getGePrice(), groundItem.getHaPrice())); @@ -500,8 +500,8 @@ public class GroundItemsPlugin extends Plugin final int price = itemPrice <= 0 ? itemComposition.getPrice() : itemPrice; final int haPrice = Math.round(itemComposition.getPrice() * Constants.HIGH_ALCHEMY_MULTIPLIER) * quantity; final int gePrice = quantity * price; - final Color hidden = getHidden(itemComposition.getName(), gePrice, haPrice, itemComposition.isTradeable()); - final Color highlighted = getHighlighted(itemComposition.getName(), gePrice, haPrice); + final Color hidden = getHidden(new NamedQuantity(itemComposition.getName(), quantity), gePrice, haPrice, itemComposition.isTradeable()); + final Color highlighted = getHighlighted(new NamedQuantity(itemComposition.getName(), quantity), gePrice, haPrice); final Color color = getItemColor(highlighted, hidden); final boolean canBeRecolored = highlighted != null || (hidden != null && config.recolorMenuHiddenItems()); @@ -569,7 +569,7 @@ public class GroundItemsPlugin extends Plugin config.setHighlightedItem(Text.toCSV(highlightedItemSet)); } - Color getHighlighted(String item, int gePrice, int haPrice) + Color getHighlighted(NamedQuantity item, int gePrice, int haPrice) { if (TRUE.equals(highlightedItems.getUnchecked(item))) { @@ -611,7 +611,7 @@ public class GroundItemsPlugin extends Plugin return null; } - Color getHidden(String item, int gePrice, int haPrice, boolean isTradeable) + Color getHidden(NamedQuantity item, int gePrice, int haPrice, boolean isTradeable) { final boolean isExplicitHidden = TRUE.equals(hiddenItems.getUnchecked(item)); final boolean isExplicitHighlight = TRUE.equals(highlightedItems.getUnchecked(item)); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/ItemThreshold.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/ItemThreshold.java new file mode 100644 index 0000000000..b92522bc1f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/ItemThreshold.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020, dekvall + * 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.grounditems; + +import com.google.common.base.Strings; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.Value; + +@Value +class ItemThreshold +{ + enum Inequality + { + LESS_THAN, + MORE_THAN + } + + private static final Pattern QUANTITY_THRESHOLD_PATTERN = Pattern.compile("(.+)(<|>)\\s*(\\d+)"); + + private final String itemName; + private final int quantity; + private final Inequality inequality; + + static ItemThreshold fromConfigEntry(String entry) + { + if (Strings.isNullOrEmpty(entry)) + { + return null; + } + + Matcher matcher = QUANTITY_THRESHOLD_PATTERN.matcher(entry); + + if (matcher.find()) + { + String name = matcher.group(1).trim(); + String sign = matcher.group(2); + int quantity = Integer.parseInt(matcher.group(3)); + Inequality inequality = sign.equals("<") ? Inequality.LESS_THAN : Inequality.MORE_THAN; + + return new ItemThreshold(name, quantity, inequality); + } + + return new ItemThreshold(entry, 0, Inequality.MORE_THAN); + } + + boolean quantityHolds(int itemCount) + { + if (inequality == Inequality.LESS_THAN) + { + return itemCount < quantity; + } + else + { + return itemCount > quantity; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/NamedQuantity.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/NamedQuantity.java new file mode 100644 index 0000000000..1d834089fc --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/NamedQuantity.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020, dekvall + * 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.grounditems; + +import lombok.RequiredArgsConstructor; +import lombok.Value; + +@Value +@RequiredArgsConstructor +class NamedQuantity +{ + private final String name; + private final int quantity; + + NamedQuantity(GroundItem groundItem) + { + this(groundItem.getName(), groundItem.getQuantity()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/WildcardMatchLoader.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/WildcardMatchLoader.java index ff7e94102e..7519bbd351 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/WildcardMatchLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/WildcardMatchLoader.java @@ -27,31 +27,37 @@ package net.runelite.client.plugins.grounditems; import com.google.common.base.Strings; import com.google.common.cache.CacheLoader; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import net.runelite.client.util.WildcardMatcher; -class WildcardMatchLoader extends CacheLoader +class WildcardMatchLoader extends CacheLoader { - private final List nameFilters; + private final List itemThresholds; - WildcardMatchLoader(List nameFilters) + WildcardMatchLoader(List configEntries) { - this.nameFilters = nameFilters; + this.itemThresholds = configEntries.stream() + .map(ItemThreshold::fromConfigEntry) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } @Override - public Boolean load(@Nonnull final String key) + public Boolean load(@Nonnull final NamedQuantity key) { - if (Strings.isNullOrEmpty(key)) + if (Strings.isNullOrEmpty(key.getName())) { return false; } - final String filteredName = key.trim(); + final String filteredName = key.getName().trim(); - for (final String filter : nameFilters) + for (final ItemThreshold entry : itemThresholds) { - if (WildcardMatcher.matches(filter, filteredName)) + if (WildcardMatcher.matches(entry.getItemName(), filteredName) + && entry.quantityHolds(key.getQuantity())) { return true; } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/WildcardMatchLoaderTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/WildcardMatchLoaderTest.java index b65dc30076..a7ade4c7d5 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/WildcardMatchLoaderTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/grounditems/WildcardMatchLoaderTest.java @@ -32,14 +32,25 @@ import org.junit.Test; public class WildcardMatchLoaderTest { @Test - public void testLoad() + public void testLoadItems() { WildcardMatchLoader loader = new WildcardMatchLoader(Arrays.asList("rune*", "Abyssal whip")); - assertTrue(loader.load("rune pouch")); - assertTrue(loader.load("Rune pouch")); - assertFalse(loader.load("Adamant dagger")); - assertTrue(loader.load("Runeite Ore")); - assertTrue(loader.load("Abyssal whip")); - assertFalse(loader.load("Abyssal dagger")); + assertTrue(loader.load(new NamedQuantity("rune pouch", 1))); + assertTrue(loader.load(new NamedQuantity("Rune pouch", 1))); + assertFalse(loader.load(new NamedQuantity("Adamant dagger", 1))); + assertTrue(loader.load(new NamedQuantity("Runeite Ore", 1))); + assertTrue(loader.load(new NamedQuantity("Abyssal whip", 1))); + assertFalse(loader.load(new NamedQuantity("Abyssal dagger", 1))); } -} \ No newline at end of file + + @Test + public void testLoadQuantities() + { + WildcardMatchLoader loader = new WildcardMatchLoader(Arrays.asList("rune* < 3", "*whip>3", "nature*<5", "*rune > 30")); + assertTrue(loader.load(new NamedQuantity("Nature Rune", 50))); + assertFalse(loader.load(new NamedQuantity("Nature Impling", 5))); + assertTrue(loader.load(new NamedQuantity("Abyssal whip", 4))); + assertFalse(loader.load(new NamedQuantity("Abyssal dagger", 1))); + assertTrue(loader.load(new NamedQuantity("Rune Longsword", 2))); + } +} From af7647e204a6a839d4c8c2ea7945405d1190c76f Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Fri, 6 Mar 2020 19:46:55 -0800 Subject: [PATCH 05/25] HotColdLocation: Center some location spots Center some hot-cold locations as reported and verified from the mega issue. Note: Because this commit makes adjustments to some locations relied upon in the hot-cold solver class test, some tests must be adjusted in order to keep passing. Ref: #9601 --- .../cluescrolls/clues/hotcold/HotColdLocation.java | 12 ++++++------ .../cluescrolls/clues/hotcold/HotColdSolverTest.java | 5 +++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java index 012bb71e76..32cb988b8c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java @@ -74,9 +74,9 @@ public enum HotColdLocation FELDIP_HILLS_JIGGIG(new WorldPoint(2409, 3053, 0), FELDIP_HILLS, "West of Jiggig, east of the fairy ring bkp."), FELDIP_HILLS_SW(new WorldPoint(2586, 2897, 0), FELDIP_HILLS, "West of the southeasternmost lake in Feldip Hills."), FELDIP_HILLS_GNOME_GLITER(new WorldPoint(2555, 2972, 0), FELDIP_HILLS, "East of the gnome glider (Lemantolly Undri)."), - FELDIP_HILLS_RANTZ(new WorldPoint(2611, 2946, 0), FELDIP_HILLS, "South of Rantz, six steps west of the empty glass bottles."), + FELDIP_HILLS_RANTZ(new WorldPoint(2611, 2950, 0), FELDIP_HILLS, "South of Rantz, west of the empty glass bottles."), FELDIP_HILLS_SOUTH(new WorldPoint(2487, 3005, 0), FELDIP_HILLS, "South of Jiggig."), - FELDIP_HILLS_RED_CHIN(new WorldPoint(2532, 2900, 0), FELDIP_HILLS, "Outside the red chinchompa hunting ground entrance, south of the Hunting expert's hut."), + FELDIP_HILLS_RED_CHIN(new WorldPoint(2530, 2901, 0), FELDIP_HILLS, "Outside the red chinchompa hunting ground entrance, south of the Hunting expert's hut."), FELDIP_HILLS_SE(new WorldPoint(2567, 2916, 0), FELDIP_HILLS, "South-east of the ∩-shaped lake, near the icon."), FELDIP_HILLS_CW_BALLOON(new WorldPoint(2452, 3108, 0), FELDIP_HILLS, "Directly west of the Castle Wars balloon."), FREMENNIK_PROVINCE_MTN_CAMP(new WorldPoint(2800, 3669, 0), FREMENNIK_PROVINCE, "At the Mountain Camp."), @@ -90,7 +90,7 @@ public enum HotColdLocation FREMENNIK_PROVINCE_WEST_ISLES_MINE(new WorldPoint(2313, 3854, 0), FREMENNIK_PROVINCE, "West Fremennik Isles mine."), FREMENNIK_PROVINCE_WEST_JATIZSO_ENTRANCE(new WorldPoint(2393, 3812, 0), FREMENNIK_PROVINCE, "West of the Jatizso mine entrance."), FREMENNIK_PROVINCE_PIRATES_COVE(new WorldPoint(2210, 3814, 0), FREMENNIK_PROVINCE, "Pirates' Cove"), - FREMENNIK_PROVINCE_ASTRAL_ALTER(new WorldPoint(2147, 3862, 0), FREMENNIK_PROVINCE, "Astral altar"), + FREMENNIK_PROVINCE_ASTRAL_ALTER(new WorldPoint(2149, 3865, 0), FREMENNIK_PROVINCE, "Astral altar"), FREMENNIK_PROVINCE_LUNAR_VILLAGE(new WorldPoint(2084, 3916, 0), FREMENNIK_PROVINCE, "Lunar Isle, inside the village."), FREMENNIK_PROVINCE_LUNAR_NORTH(new WorldPoint(2106, 3949, 0), FREMENNIK_PROVINCE, "Lunar Isle, north of the village."), ICE_MOUNTAIN(true, new WorldPoint(3007, 3475, 0), MISTHALIN, "Atop Ice Mountain"), @@ -104,7 +104,7 @@ public enum HotColdLocation KANDARIN_NECRO_TOWER(new WorldPoint(2667, 3241, 0), KANDARIN, "Ground floor inside the Necromancer Tower. Easily accessed by using fairy ring code djp."), KANDARIN_FIGHT_ARENA(new WorldPoint(2587, 3135, 0), KANDARIN, "South of the Fight Arena, north-west of the Nightmare Zone."), KANDARIN_TREE_GNOME_VILLAGE(new WorldPoint(2526, 3160, 0), KANDARIN, "Tree Gnome Village, near the general store icon."), - KANDARIN_GRAVE_OF_SCORPIUS(new WorldPoint(2464, 3228, 0), KANDARIN, "Grave of Scorpius"), + KANDARIN_GRAVE_OF_SCORPIUS(new WorldPoint(2467, 3227, 0), KANDARIN, "Grave of Scorpius"), KANDARIN_KHAZARD_BATTLEFIELD(new WorldPoint(2522, 3252, 0), KANDARIN, "Khazard Battlefield, south of Tracker gnome 2."), KANDARIN_WEST_ARDY(new WorldPoint(2535, 3322, 0), KANDARIN, "West Ardougne, near the staircase outside the Civic Office."), KANDARIN_SW_TREE_GNOME_STRONGHOLD(new WorldPoint(2411, 3429, 0), KANDARIN, "South-west Tree Gnome Stronghold"), @@ -120,7 +120,7 @@ public enum HotColdLocation KARAMJA_CRASH_ISLAND(new WorldPoint(2909, 2737, 0), KARAMJA, "Northern part of Crash Island."), LUMBRIDGE_COW_FIELD(true, new WorldPoint(3174, 3336, 0), MISTHALIN, "Cow field north of Lumbridge"), MISTHALIN_VARROCK_STONE_CIRCLE(new WorldPoint(3225, 3356, 0), MISTHALIN, "South of the stone circle near Varrock's entrance."), - MISTHALIN_LUMBRIDGE(new WorldPoint(3238, 3169, 0), MISTHALIN, "Just north-west of the Lumbridge Fishing tutor."), + MISTHALIN_LUMBRIDGE(new WorldPoint(3234, 3169, 0), MISTHALIN, "Just north-west of the Lumbridge Fishing tutor."), MISTHALIN_LUMBRIDGE_2(new WorldPoint(3170, 3278, 0), MISTHALIN, "North of the pond between Lumbridge and Draynor Village."), MISTHALIN_GERTUDES(new WorldPoint(3154, 3421, 0), MISTHALIN, "North-east of Gertrude's house west of Varrock."), MISTHALIN_DRAYNOR_BANK(new WorldPoint(3098, 3234, 0), MISTHALIN, "South of Draynor Village bank."), @@ -153,7 +153,7 @@ public enum HotColdLocation WILDERNESS_28(new WorldPoint(3377, 3737, 0), WILDERNESS, "East of Venenatis' nest, level 28 Wilderness."), WILDERNESS_32(new WorldPoint(3311, 3773, 0), WILDERNESS, "North of Venenatis' nest, level 32 Wilderness."), WILDERNESS_35(new WorldPoint(3153, 3795, 0), WILDERNESS, "East of the Wilderness canoe exit, level 35 Wilderness."), - WILDERNESS_37(new WorldPoint(2975, 3811, 0), WILDERNESS, "South-east of the Chaos Temple, level 37 Wilderness."), + WILDERNESS_37(new WorldPoint(2974, 3814, 0), WILDERNESS, "South-east of the Chaos Temple, level 37 Wilderness."), WILDERNESS_38(new WorldPoint(3293, 3813, 0), WILDERNESS, "South of Callisto, level 38 Wilderness."), WILDERNESS_49(new WorldPoint(3140, 3910, 0), WILDERNESS, "South-west of the Deserted Keep, level 49 Wilderness."), WILDERNESS_54(new WorldPoint(2981, 3944, 0), WILDERNESS, "West of the Wilderness Agility Course, level 54 Wilderness."), diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java index 37f87189dd..a6455352e1 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java @@ -109,11 +109,13 @@ public class HotColdSolverTest final HotColdSolver solver = createHotColdSolver(); final Set firstLocationsSet = Sets.immutableEnumSet( HotColdLocation.FELDIP_HILLS_GNOME_GLITER, + HotColdLocation.FELDIP_HILLS_RANTZ, HotColdLocation.FELDIP_HILLS_RED_CHIN, HotColdLocation.KARAMJA_KHARAZI_NE, HotColdLocation.KARAMJA_CRASH_ISLAND); final Set secondLocationsSet = firstLocationsSet.stream() - .filter(location -> location != HotColdLocation.FELDIP_HILLS_GNOME_GLITER) + .filter(location -> location != HotColdLocation.FELDIP_HILLS_GNOME_GLITER + && location != HotColdLocation.FELDIP_HILLS_RANTZ) .collect(Collectors.toSet()); final Set thirdLocationSet = secondLocationsSet.stream() .filter(location -> location != HotColdLocation.FELDIP_HILLS_RED_CHIN) @@ -139,7 +141,6 @@ public class HotColdSolverTest HotColdLocation.KARAMJA_KHARAZI_SW, HotColdLocation.KARAMJA_CRASH_ISLAND, HotColdLocation.FELDIP_HILLS_SW, - HotColdLocation.FELDIP_HILLS_RANTZ, HotColdLocation.FELDIP_HILLS_RED_CHIN, HotColdLocation.FELDIP_HILLS_SE)); From 6381cc18293a08cb6811251090799a4cb7ac1561 Mon Sep 17 00:00:00 2001 From: BrandtHill <38387397+BrandtHill@users.noreply.github.com> Date: Fri, 13 Mar 2020 11:48:52 -0500 Subject: [PATCH 06/25] clues: update clue text for stealing from ardougne chest --- .../client/plugins/cluescrolls/clues/SkillChallengeClue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java index 596d2ae821..1764111b28 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java @@ -133,7 +133,7 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll, Nam new SkillChallengeClue("Score a goal in skullball.", true, any("Ring of Charos", item(ItemID.RING_OF_CHAROS), item(ItemID.RING_OF_CHAROSA))), new SkillChallengeClue("Complete a lap of Ape atoll agility course.", true, any("Ninja Monkey Greegree", item(ItemID.NINJA_MONKEY_GREEGREE), item(ItemID.NINJA_MONKEY_GREEGREE_4025), item(ItemID.KRUK_MONKEY_GREEGREE))), new SkillChallengeClue("Create a super defence potion.", item(ItemID.CADANTINE_POTION_UNF), item(ItemID.WHITE_BERRIES)), - new SkillChallengeClue("Steal from a chest in King Lathas' castle in East Ardougne."), + new SkillChallengeClue("Steal from a chest in Ardougne Castle."), new SkillChallengeClue("Craft a green d'hide body.", xOfItem(ItemID.GREEN_DRAGON_LEATHER, 3), item(ItemID.NEEDLE), item(ItemID.THREAD)), new SkillChallengeClue("String a yew longbow.", item(ItemID.YEW_LONGBOW_U), item(ItemID.BOW_STRING)), new SkillChallengeClue("Kill a Dust Devil.", "slay a dust devil.", true, any("Facemask or Slayer Helmet", item(ItemID.FACEMASK), item(ItemID.SLAYER_HELMET), item(ItemID. SLAYER_HELMET_I), item(ItemID. BLACK_SLAYER_HELMET), item(ItemID. BLACK_SLAYER_HELMET_I), item(ItemID. PURPLE_SLAYER_HELMET), item(ItemID. PURPLE_SLAYER_HELMET_I), item(ItemID. RED_SLAYER_HELMET), item(ItemID. RED_SLAYER_HELMET_I), item(ItemID.GREEN_SLAYER_HELMET), item(ItemID. GREEN_SLAYER_HELMET_I), item(ItemID. TURQUOISE_SLAYER_HELMET), item(ItemID. TURQUOISE_SLAYER_HELMET_I), item(ItemID. HYDRA_SLAYER_HELMET), item(ItemID. HYDRA_SLAYER_HELMET_I))), From 85c0ed29a6485ac01062ed7269a2cd723fbbf2a7 Mon Sep 17 00:00:00 2001 From: dekvall Date: Sat, 14 Mar 2020 01:15:58 +0100 Subject: [PATCH 07/25] menu entry swapper: update essence mine description to include all npcs --- .../client/plugins/menuentryswapper/MenuEntrySwapperConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java index 2e929ca6ba..1e81d1d338 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java @@ -415,7 +415,7 @@ public interface MenuEntrySwapperConfig extends Config @ConfigItem( keyName = "swapEssenceMineTeleport", name = "Essence Mine Teleport", - description = "Swaps Talk-To with Teleport for Wizard Distentor and Aubury." + description = "Swaps Talk-To with Teleport for NPCs which teleport you to the essence mine" ) default boolean swapEssenceMineTeleport() { From 3236ff67de30201c336fc942d9aa075729e5b500 Mon Sep 17 00:00:00 2001 From: Austin Date: Fri, 13 Mar 2020 23:49:35 -0600 Subject: [PATCH 08/25] Added nightmare dungeon and nightmare boss to discord game events. --- .../runelite/client/plugins/discord/DiscordGameEventType.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java index 01b6271c2d..86df245d5c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java @@ -85,6 +85,7 @@ enum DiscordGameEventType BOSS_WINTERTODT("Wintertodt", DiscordAreaType.BOSSES, 6462), BOSS_ZALCANO("Zalcano", DiscordAreaType.BOSSES, 13250), BOSS_ZULRAH("Zulrah", DiscordAreaType.BOSSES, 9007), + BOSS_NIGHTMARE("Nightmare of Ashihama", DiscordAreaType.BOSSES, 15515), // Cities CITY_AL_KHARID("Al Kharid" , DiscordAreaType.CITIES, 13105, 13106), @@ -225,6 +226,7 @@ enum DiscordGameEventType DUNGEON_WITCHAVEN_SHRINE("Witchhaven Shrine Dungeon", DiscordAreaType.DUNGEONS, 10903), DUNGEON_YANILLE_AGILITY("Yanille Agility Dungeon", DiscordAreaType.DUNGEONS, 10388), DUNGEON_MOTHERLODE_MINE("Motherlode Mine", DiscordAreaType.DUNGEONS, 14679, 14680, 14681, 14935, 14936, 14937, 15191, 15192, 15193), + DUNGEON_NIGHTMARE("Nightmare Dungeon", DiscordAreaType.DUNGEONS, 14999, 15000, 15001, 15255, 15256, 15257, 15511, 15512, 15513), // Minigames MG_BARBARIAN_ASSAULT("Barbarian Assault", DiscordAreaType.MINIGAMES, 10332), From 82cef9329663833ee800575d32b52c97fda34e4a Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 14 Mar 2020 12:07:22 -0400 Subject: [PATCH 09/25] opponentinfo: account for panel border in overlay size --- .../client/plugins/opponentinfo/OpponentInfoOverlay.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java index d78036217c..1ebc861ba3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java @@ -151,8 +151,8 @@ class OpponentInfoOverlay extends Overlay panelComponent.getChildren().clear(); // Opponent name - int textWidth = Math.max(ComponentConstants.STANDARD_WIDTH, fontMetrics.stringWidth(opponentName)); - panelComponent.setPreferredSize(new Dimension(textWidth, 0)); + int panelWidth = Math.max(ComponentConstants.STANDARD_WIDTH, fontMetrics.stringWidth(opponentName) + ComponentConstants.STANDARD_BORDER + ComponentConstants.STANDARD_BORDER); + panelComponent.setPreferredSize(new Dimension(panelWidth, 0)); panelComponent.getChildren().add(TitleComponent.builder() .text(opponentName) .build()); @@ -221,8 +221,8 @@ class OpponentInfoOverlay extends Overlay // Opponents opponent if (opponentsOpponentName != null && opponentInfoConfig.showOpponentsOpponent()) { - textWidth = Math.max(textWidth, fontMetrics.stringWidth(opponentsOpponentName)); - panelComponent.setPreferredSize(new Dimension(textWidth, 0)); + panelWidth = Math.max(panelWidth, fontMetrics.stringWidth(opponentsOpponentName) + ComponentConstants.STANDARD_BORDER + ComponentConstants.STANDARD_BORDER); + panelComponent.setPreferredSize(new Dimension(panelWidth, 0)); panelComponent.getChildren().add(TitleComponent.builder() .text(opponentsOpponentName) .build()); From 623421350537b6c4f37e285ea4ed8cc29f78427d Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Sun, 8 Mar 2020 22:31:25 +0100 Subject: [PATCH 10/25] Migrate XpGlobesOverlay tooltips to component tooltips Signed-off-by: Tomas Slusny Co-Authored-By: Jordan --- .../plugins/xpglobes/XpGlobesOverlay.java | 23 ++++++++++--------- .../overlay/components/TooltipComponent.java | 1 - 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java index 6b5b23b349..4b2654948c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java @@ -53,6 +53,8 @@ import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; public class XpGlobesOverlay extends Overlay { @@ -66,8 +68,9 @@ public class XpGlobesOverlay extends Overlay private final XpGlobesPlugin plugin; private final XpGlobesConfig config; private final XpTrackerService xpTrackerService; - private final PanelComponent xpTooltip = new PanelComponent(); + private final TooltipManager tooltipManager; private final SkillIconManager iconManager; + private final Tooltip xpTooltip = new Tooltip(new PanelComponent()); @Inject private XpGlobesOverlay( @@ -75,7 +78,8 @@ public class XpGlobesOverlay extends Overlay XpGlobesPlugin plugin, XpGlobesConfig config, XpTrackerService xpTrackerService, - SkillIconManager iconManager) + SkillIconManager iconManager, + TooltipManager tooltipManager) { super(plugin); this.iconManager = iconManager; @@ -83,6 +87,8 @@ public class XpGlobesOverlay extends Overlay this.plugin = plugin; this.config = config; this.xpTrackerService = xpTrackerService; + this.tooltipManager = tooltipManager; + this.xpTooltip.getComponent().setPreferredSize(new Dimension(TOOLTIP_RECT_SIZE_X, 0)); setPosition(OverlayPosition.TOP_CENTER); getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "XP Globes overlay")); } @@ -150,7 +156,7 @@ public class XpGlobesOverlay extends Overlay if (config.enableTooltips()) { - drawTooltip(graphics, skillToDraw, goalXp, backgroundCircle); + drawTooltip(skillToDraw, goalXp); } } @@ -229,12 +235,8 @@ public class XpGlobesOverlay extends Overlay ); } - private void drawTooltip(Graphics2D graphics, XpGlobe mouseOverSkill, int goalXp, Ellipse2D drawnGlobe) + private void drawTooltip(XpGlobe mouseOverSkill, int goalXp) { - //draw tooltip under the globe of the mouse location - int x = (int) drawnGlobe.getX() - (TOOLTIP_RECT_SIZE_X / 2) + (config.xpOrbSize() / 2); - int y = (int) drawnGlobe.getY() + config.xpOrbSize() + 10; - // reset the timer on XpGlobe to prevent it from disappearing while hovered over it mouseOverSkill.setTime(Instant.now()); @@ -244,9 +246,8 @@ public class XpGlobesOverlay extends Overlay DecimalFormat decimalFormat = new DecimalFormat("###,###,###"); String skillCurrentXp = decimalFormat.format(mouseOverSkill.getCurrentXp()); + final PanelComponent xpTooltip = (PanelComponent) this.xpTooltip.getComponent(); xpTooltip.getChildren().clear(); - xpTooltip.setPreferredLocation(new java.awt.Point(x, y)); - xpTooltip.setPreferredSize(new Dimension(TOOLTIP_RECT_SIZE_X, 0)); xpTooltip.getChildren().add(LineComponent.builder() .left(skillName) @@ -303,6 +304,6 @@ public class XpGlobesOverlay extends Overlay } } - xpTooltip.render(graphics); + tooltipManager.add(this.xpTooltip); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java index fee7332497..cd917c38a8 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java @@ -240,6 +240,5 @@ public class TooltipComponent implements LayoutableRenderableEntity @Override public void setPreferredSize(Dimension dimension) { - } } From 7672efda3fb895b927105bdf856e6965852a484f Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 15 Mar 2020 21:17:56 -0400 Subject: [PATCH 11/25] experience: remove unnecessary Math.floor() calls --- runelite-api/src/main/java/net/runelite/api/Experience.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/Experience.java b/runelite-api/src/main/java/net/runelite/api/Experience.java index d83a61c97b..6fa91919dc 100644 --- a/runelite-api/src/main/java/net/runelite/api/Experience.java +++ b/runelite-api/src/main/java/net/runelite/api/Experience.java @@ -127,8 +127,8 @@ public class Experience private static double getMeleeRangeOrMagicCombatLevelContribution(int attackLevel, int strengthLevel, int magicLevel, int rangeLevel) { double melee = 0.325 * (attackLevel + strengthLevel); - double range = 0.325 * (Math.floor(rangeLevel / 2) + rangeLevel); - double magic = 0.325 * (Math.floor(magicLevel / 2) + magicLevel); + double range = 0.325 * (rangeLevel / 2 + rangeLevel); + double magic = 0.325 * (magicLevel / 2 + magicLevel); return Math.max(melee, Math.max(range, magic)); } @@ -152,7 +152,7 @@ public class Experience int defenceLevel, int hitpointsLevel, int magicLevel, int rangeLevel, int prayerLevel) { - double base = 0.25 * (defenceLevel + hitpointsLevel + Math.floor(prayerLevel / 2)); + double base = 0.25 * (defenceLevel + hitpointsLevel + (prayerLevel / 2)); double typeContribution = getMeleeRangeOrMagicCombatLevelContribution(attackLevel, strengthLevel, magicLevel, rangeLevel); From 7c8095785f4bcb33d024183fe02954a63f63fc52 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 13 Mar 2020 23:47:58 -0400 Subject: [PATCH 12/25] linepanelcomponent: remove empty string text component renders --- .../ui/overlay/components/LineComponent.java | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java index f6c2f5e77c..b5ce2b1fc7 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java @@ -73,6 +73,7 @@ public class LineComponent implements LayoutableRenderableEntity int y = baseY; final int leftFullWidth = getLineWidth(left, metrics); final int rightFullWidth = getLineWidth(right, metrics); + final TextComponent textComponent = new TextComponent(); if (preferredSize.width < leftFullWidth + rightFullWidth) { @@ -92,30 +93,24 @@ public class LineComponent implements LayoutableRenderableEntity for (int i = 0; i < lineCount; i++) { - String leftText = ""; - String rightText = ""; - if (i < leftSplitLines.length) { - leftText = leftSplitLines[i]; + final String leftText = leftSplitLines[i]; + textComponent.setPosition(new Point(x, y)); + textComponent.setText(leftText); + textComponent.setColor(leftColor); + textComponent.render(graphics); } if (i < rightSplitLines.length) { - rightText = rightSplitLines[i]; + final String rightText = rightSplitLines[i]; + textComponent.setPosition(new Point(x + preferredSize.width - getLineWidth(rightText, metrics), y)); + textComponent.setText(rightText); + textComponent.setColor(rightColor); + textComponent.render(graphics); } - final TextComponent leftLineComponent = new TextComponent(); - leftLineComponent.setPosition(new Point(x, y)); - leftLineComponent.setText(leftText); - leftLineComponent.setColor(leftColor); - leftLineComponent.render(graphics); - - final TextComponent rightLineComponent = new TextComponent(); - rightLineComponent.setPosition(new Point(x + leftSmallWidth + rightSmallWidth - getLineWidth(rightText, metrics), y)); - rightLineComponent.setText(rightText); - rightLineComponent.setColor(rightColor); - rightLineComponent.render(graphics); y += metrics.getHeight(); } @@ -125,17 +120,22 @@ public class LineComponent implements LayoutableRenderableEntity return dimension; } - final TextComponent leftLineComponent = new TextComponent(); - leftLineComponent.setPosition(new Point(x, y)); - leftLineComponent.setText(left); - leftLineComponent.setColor(leftColor); - leftLineComponent.render(graphics); + if (!left.isEmpty()) + { + textComponent.setPosition(new Point(x, y)); + textComponent.setText(left); + textComponent.setColor(leftColor); + textComponent.render(graphics); + } + + if (!right.isEmpty()) + { + textComponent.setPosition(new Point(x + preferredSize.width - rightFullWidth, y)); + textComponent.setText(right); + textComponent.setColor(rightColor); + textComponent.render(graphics); + } - final TextComponent rightLineComponent = new TextComponent(); - rightLineComponent.setPosition(new Point(x + preferredSize.width - getLineWidth(right, metrics), y)); - rightLineComponent.setText(right); - rightLineComponent.setColor(rightColor); - rightLineComponent.render(graphics); y += metrics.getHeight(); final Dimension dimension = new Dimension(preferredSize.width, y - baseY); From dd18626d1536e9344dba1128a4b2065e1c5fa9a9 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 14 Mar 2020 12:52:20 -0400 Subject: [PATCH 13/25] components: use common Text.removeTags This was only removing color tags before, however neither text component nor line component can correctly handle the other tags anyway, so remove all tags --- .../client/ui/overlay/components/LineComponent.java | 3 ++- .../client/ui/overlay/components/TextComponent.java | 11 +++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java index b5ce2b1fc7..20638e7874 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java @@ -35,6 +35,7 @@ import java.awt.Rectangle; import lombok.Builder; import lombok.Getter; import lombok.Setter; +import net.runelite.client.util.Text; @Setter @Builder @@ -146,7 +147,7 @@ public class LineComponent implements LayoutableRenderableEntity private static int getLineWidth(final String line, final FontMetrics metrics) { - return metrics.stringWidth(TextComponent.textWithoutColTags(line)); + return metrics.stringWidth(Text.removeTags(line)); } private static String[] lineBreakText(String text, int maxWidth, FontMetrics metrics) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java index 98532a8d7c..97e4c9db65 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java @@ -32,36 +32,31 @@ import java.awt.Point; import java.util.regex.Pattern; import lombok.Setter; import net.runelite.client.ui.overlay.RenderableEntity; +import net.runelite.client.util.Text; @Setter public class TextComponent implements RenderableEntity { private static final String COL_TAG_REGEX = "()"; private static final Pattern COL_TAG_PATTERN_W_LOOKAHEAD = Pattern.compile("(?=" + COL_TAG_REGEX + ")"); - private static final Pattern COL_TAG_PATTERN = Pattern.compile(COL_TAG_REGEX); private String text; private Point position = new Point(); private Color color = Color.WHITE; - public static String textWithoutColTags(String text) - { - return COL_TAG_PATTERN.matcher(text).replaceAll(""); - } - @Override public Dimension render(Graphics2D graphics) { final FontMetrics fontMetrics = graphics.getFontMetrics(); - if (COL_TAG_PATTERN.matcher(text).find()) + if (COL_TAG_PATTERN_W_LOOKAHEAD.matcher(text).find()) { final String[] parts = COL_TAG_PATTERN_W_LOOKAHEAD.split(text); int x = position.x; for (String textSplitOnCol : parts) { - final String textWithoutCol = textWithoutColTags(textSplitOnCol); + final String textWithoutCol = Text.removeTags(textSplitOnCol); final String colColor = textSplitOnCol.substring(textSplitOnCol.indexOf("=") + 1, textSplitOnCol.indexOf(">")); // shadow From 43998972cf586d7c06169015a0946bf76901b0c4 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 14 Mar 2020 13:21:51 -0400 Subject: [PATCH 14/25] panelcomponent: fix removing final gap from total width/height --- .../client/ui/overlay/components/PanelComponent.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java index 0d81a5bf18..5fb373621c 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java @@ -163,8 +163,14 @@ public class PanelComponent implements LayoutableRenderableEntity } // Remove last child gap - totalWidth -= gap.x; - totalHeight -= gap.y; + if (orientation == ComponentOrientation.HORIZONTAL) + { + totalWidth -= gap.x; + } + else // VERTICAL + { + totalHeight -= gap.y; + } // Cache children bounds childDimensions.setSize(totalWidth, totalHeight); From 491e837207a32932806987c2a4bdb1e28431b0f9 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 16 Mar 2020 17:37:10 -0400 Subject: [PATCH 15/25] client: synchronize some calls to ImageIO.read() ImageIO is not thread safe, see also 054dd4852dec76bf49fc13f81e6ed96790b0ddd1 --- .../runelite/client/plugins/discord/DiscordPlugin.java | 6 +++++- .../java/net/runelite/client/ui/FatalErrorDialog.java | 9 ++++----- .../main/java/net/runelite/client/ui/SplashScreen.java | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java index c1537d8f40..513ce7bff7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java @@ -292,7 +292,11 @@ public class DiscordPlugin extends Plugin } final InputStream inputStream = response.body().byteStream(); - final BufferedImage image = ImageIO.read(inputStream); + final BufferedImage image; + synchronized (ImageIO.class) + { + image = ImageIO.read(inputStream); + } memberById.setAvatar(image); } finally diff --git a/runelite-client/src/main/java/net/runelite/client/ui/FatalErrorDialog.java b/runelite-client/src/main/java/net/runelite/client/ui/FatalErrorDialog.java index 8563595685..dcf1b9fe48 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/FatalErrorDialog.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/FatalErrorDialog.java @@ -33,12 +33,10 @@ import java.awt.Font; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; -import java.io.IOException; import java.net.ConnectException; import java.net.UnknownHostException; import java.security.GeneralSecurityException; import java.util.concurrent.atomic.AtomicBoolean; -import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ImageIcon; @@ -52,8 +50,9 @@ import javax.swing.border.EmptyBorder; import lombok.extern.slf4j.Slf4j; import net.runelite.client.RuneLite; import net.runelite.client.RuneLiteProperties; -import net.runelite.client.util.VerificationException; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.LinkBrowser; +import net.runelite.client.util.VerificationException; @Slf4j public class FatalErrorDialog extends JDialog @@ -82,7 +81,7 @@ public class FatalErrorDialog extends JDialog try { - BufferedImage logo = ImageIO.read(SplashScreen.class.getResourceAsStream("runelite_transparent.png")); + BufferedImage logo = ImageUtil.getResourceStreamFromClass(FatalErrorDialog.class, "runelite_transparent.png"); setIconImage(logo); JLabel runelite = new JLabel(); @@ -92,7 +91,7 @@ public class FatalErrorDialog extends JDialog runelite.setOpaque(true); rightColumn.add(runelite); } - catch (IOException e) + catch (RuntimeException e) { } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/SplashScreen.java b/runelite-client/src/main/java/net/runelite/client/ui/SplashScreen.java index 59f0b13610..77cac7340b 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/SplashScreen.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/SplashScreen.java @@ -33,7 +33,6 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import javax.annotation.Nullable; -import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; @@ -46,6 +45,7 @@ import javax.swing.border.EmptyBorder; import javax.swing.plaf.basic.BasicProgressBarUI; import lombok.extern.slf4j.Slf4j; import net.runelite.client.ui.skin.SubstanceRuneLiteLookAndFeel; +import net.runelite.client.util.ImageUtil; import org.pushingpixels.substance.internal.SubstanceSynapse; @Slf4j @@ -68,7 +68,7 @@ public class SplashScreen extends JFrame implements ActionListener private SplashScreen() throws IOException { - BufferedImage logo = ImageIO.read(SplashScreen.class.getResourceAsStream("runelite_transparent.png")); + BufferedImage logo = ImageUtil.getResourceStreamFromClass(SplashScreen.class, "runelite_transparent.png"); setTitle("RuneLite Launcher"); From 51f562b547aeb1c6df61ecb4963b1cf2e8143975 Mon Sep 17 00:00:00 2001 From: ThatGamerBlue Date: Fri, 13 Mar 2020 17:27:02 +0000 Subject: [PATCH 16/25] scripts: add FriendUpdate and IgnoreUpdate Co-authored-by: Adam --- .../src/main/scripts/FriendUpdate.hash | 1 + .../src/main/scripts/FriendUpdate.rs2asm | 561 ++++++++++++++++++ .../src/main/scripts/IgnoreUpdate.hash | 1 + .../src/main/scripts/IgnoreUpdate.rs2asm | 320 ++++++++++ 4 files changed, 883 insertions(+) create mode 100644 runelite-client/src/main/scripts/FriendUpdate.hash create mode 100644 runelite-client/src/main/scripts/FriendUpdate.rs2asm create mode 100644 runelite-client/src/main/scripts/IgnoreUpdate.hash create mode 100644 runelite-client/src/main/scripts/IgnoreUpdate.rs2asm diff --git a/runelite-client/src/main/scripts/FriendUpdate.hash b/runelite-client/src/main/scripts/FriendUpdate.hash new file mode 100644 index 0000000000..78f935d1bb --- /dev/null +++ b/runelite-client/src/main/scripts/FriendUpdate.hash @@ -0,0 +1 @@ +6DC2945220E60445B7857ECFB97908E0B28FF0E96E533BB8DC8293DC68A986C2 \ No newline at end of file diff --git a/runelite-client/src/main/scripts/FriendUpdate.rs2asm b/runelite-client/src/main/scripts/FriendUpdate.rs2asm new file mode 100644 index 0000000000..e2d838bd66 --- /dev/null +++ b/runelite-client/src/main/scripts/FriendUpdate.rs2asm @@ -0,0 +1,561 @@ +.id 125 +.int_stack_count 9 +.string_stack_count 0 +.int_var_count 16 +.string_var_count 2 + iload 1 + iconst 2 + iconst 3 + iconst 2 + sconst "Sort by name" + iload 0 + iload 1 + iload 2 + iload 3 + iload 4 + iload 5 + iload 6 + iload 7 + iload 8 + invoke 1669 + iload 2 + iconst 8 + iconst 9 + iconst 9 + sconst "Sort by last world change" + iload 0 + iload 1 + iload 2 + iload 3 + iload 4 + iload 5 + iload 6 + iload 7 + iload 8 + invoke 1669 + iload 3 + iconst 4 + iconst 5 + iconst 4 + sconst "Sort by world" + iload 0 + iload 1 + iload 2 + iload 3 + iload 4 + iload 5 + iload 6 + iload 7 + iload 8 + invoke 1669 + iload 4 + iconst 0 + iconst 1 + iconst 0 + sconst "Legacy sort" + iload 0 + iload 1 + iload 2 + iload 3 + iload 4 + iload 5 + iload 6 + iload 7 + iload 8 + invoke 1669 + iload 5 + cc_deleteall + iconst 0 + istore 9 + iconst 0 + istore 10 + sconst "" + sstore 0 + sconst "" + sstore 1 + iconst 0 + istore 11 + iconst 0 + istore 12 + iconst 15 + istore 13 + iconst -1 + istore 14 + friend_count + istore 15 + iload 15 + iconst -2 + if_icmple LABEL84 + jump LABEL105 +LABEL84: + get_varbit 8119 + iconst 1 + if_icmpeq LABEL88 + jump LABEL95 +LABEL88: + sconst "Loading friends list" + sconst "
" + sconst "Please wait..." + join_string 3 + iload 7 + if_settext + jump LABEL101 +LABEL95: + sconst "You must set a name" + sconst "
" + sconst "before using this." + join_string 3 + iload 7 + if_settext +LABEL101: + iconst 1 + iload 0 + if_sethide + jump LABEL468 +LABEL105: + iload 15 + iconst -1 + if_icmpeq LABEL109 + jump LABEL130 +LABEL109: + get_varbit 8119 + iconst 1 + if_icmpeq LABEL113 + jump LABEL120 +LABEL113: + sconst "Loading friends list" + sconst "
" + sconst "Please wait..." + join_string 3 + iload 7 + if_settext + jump LABEL126 +LABEL120: + sconst "You must set a name" + sconst "
" + sconst "before using this." + join_string 3 + iload 7 + if_settext +LABEL126: + iconst 1 + iload 0 + if_sethide + jump LABEL468 +LABEL130: + invoke 1972 + istore 14 + iload 14 + iconst 1 + if_icmpeq LABEL136 + jump LABEL141 +LABEL136: + iconst 8 + iconst 5 + iload 13 + scale + istore 13 +LABEL141: + sconst "" + iload 7 + if_settext + iconst 0 + iload 0 + if_sethide + 3628 + get_varc_int 183 + switch + 1: LABEL151 + 2: LABEL154 + 3: LABEL159 + 4: LABEL174 + 5: LABEL194 + 8: LABEL164 + 9: LABEL169 + jump LABEL213 +LABEL151: + iconst 0 + 3629 + jump LABEL213 +LABEL154: + iconst 1 + 3633 + iconst 1 + 3630 + jump LABEL213 +LABEL159: + iconst 1 + 3633 + iconst 0 + 3630 + jump LABEL213 +LABEL164: + iconst 1 + 3633 + iconst 1 + 3632 + jump LABEL213 +LABEL169: + iconst 1 + 3633 + iconst 0 + 3632 + jump LABEL213 +LABEL174: + iconst 1 + 3633 + iconst 1 + 3636 + iconst 1 + 3631 + get_varc_int 205 + switch + 3: LABEL185 + 8: LABEL188 + 9: LABEL191 + iconst 1 + 3630 + jump LABEL193 +LABEL185: + iconst 0 + 3630 + jump LABEL193 +LABEL188: + iconst 1 + 3632 + jump LABEL193 +LABEL191: + iconst 0 + 3632 +LABEL193: + jump LABEL213 +LABEL194: + iconst 1 + 3633 + iconst 1 + 3636 + iconst 0 + 3631 + get_varc_int 205 + switch + 3: LABEL205 + 8: LABEL208 + 9: LABEL211 + iconst 1 + 3630 + jump LABEL213 +LABEL205: + iconst 0 + 3630 + jump LABEL213 +LABEL208: + iconst 1 + 3632 + jump LABEL213 +LABEL211: + iconst 0 + 3632 +LABEL213: + 3639 +LABEL214: + iload 9 + iload 15 + if_icmplt LABEL218 + jump LABEL460 +LABEL218: + iload 9 + friend_getname + sstore 1 + sstore 0 + iload 5 + iconst 4 + iload 10 + cc_create + iload 10 + iconst 1 + add + istore 10 + sload 0 + cc_settext + iconst 0 + iload 13 + iconst 1 + iconst 0 + cc_setsize + iconst 0 + iload 12 + iconst 1 + iconst 0 + cc_setposition + iconst 16777215 + cc_setcolour + iconst 495 + cc_settextfont + iconst 0 + iconst 1 + iconst 0 + cc_settextalign + iconst 1 + cc_settextshadow + sconst "" + sload 0 + sconst "" + join_string 3 + cc_setopbase + iload 9 + friend_getworld + istore 11 + iload 11 + iconst 0 + if_icmpne LABEL264 + jump LABEL271 +LABEL264: + iconst 1 + sconst "Message" + cc_setop + iconst 2 + sconst "" + cc_setop + jump LABEL277 +LABEL271: + iconst 1 + sconst "" + cc_setop + iconst 2 + sconst "Message" + cc_setop +LABEL277: + iconst 3 + sconst "Delete" + cc_setop + iload 5 + iconst 5 + iload 10 + cc_create 1 + iload 10 + iconst 1 + add + istore 10 + iconst 14 + iconst 14 + iconst 0 + iconst 0 + cc_setsize 1 + sload 0 + iconst 190 + iconst 495 + parawidth + iconst 3 + add + iload 12 + iload 13 + iconst 14 + sub + iconst 2 + div + add + iconst 0 + iconst 0 + cc_setposition 1 + iconst 1093 + cc_setgraphic 1 + iconst 3355443 + cc_setgraphicshadow 1 + sload 1 + string_length + iconst 0 + if_icmpgt LABEL318 + jump LABEL367 +LABEL318: + iload 14 + iconst 1 + if_icmpeq LABEL322 + jump LABEL336 +LABEL322: + iconst 10 + sconst "Reveal previous name" + cc_setop + iconst 126 + iconst -2147483644 + sconst "event_opbase" + iconst -2147483645 + cc_getid + cc_getid 1 + sload 1 + sload 0 + sconst "isIiiss" + cc_setonop + jump LABEL364 +LABEL336: + sconst "Previous name:" + sconst "
" + sload 1 + join_string 3 + sstore 1 + iconst 526 + iconst -2147483645 + iconst -2147483643 + iload 8 + sload 1 + iconst 25 + iconst 190 + sconst "IiIsii" + cc_setonmouserepeat + iconst 40 + iload 8 + sconst "I" + cc_setonmouseleave + iconst 126 + iconst -2147483644 + sconst "event_opbase" + iconst -1 + iconst -1 + iconst -1 + sconst "null" + sconst "null" + sconst "isIiiss" + cc_setonop +LABEL364: + iconst 0 + cc_sethide 1 + jump LABEL383 +LABEL367: + iconst 40 + iload 8 + sconst "I" + cc_setonmouseover + iconst 1 + cc_sethide 1 + iconst 126 + iconst -2147483644 + sconst "event_opbase" + iconst -1 + iconst -1 + iconst -1 + sconst "null" + sconst "null" + sconst "isIiiss" + cc_setonop +LABEL383: + iload 5 + iconst 4 + iload 10 + cc_create + iload 10 + iconst 1 + add + istore 10 + iconst 0 + iload 13 + iconst 1 + iconst 0 + cc_setsize + iconst 0 + iload 12 + iconst 1 + iconst 0 + cc_setposition + iconst 495 + cc_settextfont + iconst 2 + iconst 1 + iconst 0 + cc_settextalign + iconst 1 + cc_settextshadow + iload 11 + iconst 0 + if_icmpeq LABEL413 + jump LABEL418 +LABEL413: + sconst "Offline" + cc_settext + iconst 16711680 + cc_setcolour + jump LABEL451 +LABEL418: + iload 11 + map_world + if_icmpeq LABEL422 + jump LABEL430 +LABEL422: + sconst "World " + iload 11 + tostring + join_string 2 + cc_settext + iconst 901389 + cc_setcolour + jump LABEL451 +LABEL430: + iload 11 + iconst 5000 + if_icmpgt LABEL434 + jump LABEL443 +LABEL434: + sconst "" + sconst "Classic " + iload 11 + iconst 5000 + sub + tostring + join_string 3 + cc_settext + jump LABEL449 +LABEL443: + sconst "" + sconst "World " + iload 11 + tostring + join_string 3 + cc_settext +LABEL449: + iconst 16776960 + cc_setcolour +LABEL451: + iload 9 + iconst 1 + add + iload 12 + iload 13 + add + istore 12 + istore 9 + jump LABEL214 +LABEL460: + iload 15 + iconst 1 + if_icmpge LABEL464 + jump LABEL468 +LABEL464: + iload 12 + iconst 5 + add + istore 12 +LABEL468: + iload 12 + iload 5 + if_getheight + if_icmpgt LABEL473 + jump LABEL482 +LABEL473: + iconst 0 + iload 12 + iload 5 + if_setscrollsize + iload 6 + iload 5 + get_varc_int 9 + invoke 72 + jump LABEL490 +LABEL482: + iconst 0 + iconst 0 + iload 5 + if_setscrollsize + iload 6 + iload 5 + iconst 0 + invoke 72 +LABEL490: + return diff --git a/runelite-client/src/main/scripts/IgnoreUpdate.hash b/runelite-client/src/main/scripts/IgnoreUpdate.hash new file mode 100644 index 0000000000..b10226b2e6 --- /dev/null +++ b/runelite-client/src/main/scripts/IgnoreUpdate.hash @@ -0,0 +1 @@ +256A38E234D9D44532175F4C98AA923327EE050E23D122573426D94FBF15936E \ No newline at end of file diff --git a/runelite-client/src/main/scripts/IgnoreUpdate.rs2asm b/runelite-client/src/main/scripts/IgnoreUpdate.rs2asm new file mode 100644 index 0000000000..c50a07f093 --- /dev/null +++ b/runelite-client/src/main/scripts/IgnoreUpdate.rs2asm @@ -0,0 +1,320 @@ +.id 129 +.int_stack_count 7 +.string_stack_count 0 +.int_var_count 13 +.string_var_count 2 + iload 1 + iconst 2 + iconst 3 + sconst "Sort by name" + iload 0 + iload 1 + iload 2 + iload 3 + iload 4 + iload 5 + iload 6 + invoke 1653 + iload 2 + iconst 0 + iconst 1 + sconst "Legacy sort" + iload 0 + iload 1 + iload 2 + iload 3 + iload 4 + iload 5 + iload 6 + invoke 1653 + iload 3 + cc_deleteall + iconst 0 + istore 7 + iconst 0 + istore 8 + sconst "" + sstore 0 + sconst "" + sstore 1 + iconst 0 + istore 9 + iconst 15 + istore 10 + iconst -1 + istore 11 + ignore_count + istore 12 + iload 12 + iconst 0 + if_icmplt LABEL46 + jump LABEL67 +LABEL46: + get_varbit 8119 + iconst 1 + if_icmpeq LABEL50 + jump LABEL57 +LABEL50: + sconst "Loading ignore list" + sconst "
" + sconst "Please wait..." + join_string 3 + iload 5 + if_settext + jump LABEL63 +LABEL57: + sconst "You must set a name" + sconst "
" + sconst "before using this." + join_string 3 + iload 5 + if_settext +LABEL63: + iconst 1 + iload 0 + if_sethide + jump LABEL263 +LABEL67: + invoke 1972 + istore 11 + iload 11 + iconst 1 + if_icmpeq LABEL73 + jump LABEL78 +LABEL73: + iconst 8 + iconst 5 + iload 10 + scale + istore 10 +LABEL78: + sconst "" + iload 5 + if_settext + iconst 0 + iload 0 + if_sethide + 3640 + get_varc_int 184 + switch + 1: LABEL88 + 2: LABEL91 + 3: LABEL94 + jump LABEL96 +LABEL88: + iconst 0 + 3641 + jump LABEL96 +LABEL91: + iconst 1 + 3642 + jump LABEL96 +LABEL94: + iconst 0 + 3642 +LABEL96: + 3643 +LABEL97: + iload 7 + iload 12 + if_icmplt LABEL101 + jump LABEL255 +LABEL101: + iload 7 + ignore_getname + sstore 1 + sstore 0 + iload 3 + iconst 4 + iload 8 + cc_create + iload 8 + iconst 1 + add + istore 8 + sload 0 + cc_settext + iconst 0 + iload 10 + iconst 1 + iconst 0 + cc_setsize + iconst 0 + iload 9 + iconst 1 + iconst 0 + cc_setposition + iconst 16777215 + cc_setcolour + iconst 495 + cc_settextfont + iconst 0 + iconst 1 + iconst 0 + cc_settextalign + iconst 1 + cc_settextshadow + sconst "" + sload 0 + sconst "" + join_string 3 + cc_setopbase + iconst 1 + sconst "Delete" + cc_setop + iload 3 + iconst 5 + iload 8 + cc_create 1 + iload 8 + iconst 1 + add + istore 8 + iconst 14 + iconst 14 + iconst 0 + iconst 0 + cc_setsize 1 + sload 0 + iconst 190 + iconst 495 + parawidth + iconst 3 + add + iload 9 + iload 10 + iconst 14 + sub + iconst 2 + div + add + iconst 0 + iconst 0 + cc_setposition 1 + iconst 1093 + cc_setgraphic 1 + iconst 3355443 + cc_setgraphicshadow 1 + sload 1 + string_length + iconst 0 + if_icmpgt LABEL181 + jump LABEL230 +LABEL181: + iload 11 + iconst 1 + if_icmpeq LABEL185 + jump LABEL199 +LABEL185: + iconst 10 + sconst "Reveal previous name" + cc_setop + iconst 130 + iconst -2147483644 + sconst "event_opbase" + iconst -2147483645 + cc_getid + cc_getid 1 + sload 1 + sload 0 + sconst "isIiiss" + cc_setonop + jump LABEL227 +LABEL199: + sconst "Previous name:" + sconst "
" + sload 1 + join_string 3 + sstore 1 + iconst 526 + iconst -2147483645 + iconst -2147483643 + iload 6 + sload 1 + iconst 25 + iconst 190 + sconst "IiIsii" + cc_setonmouserepeat + iconst 40 + iload 6 + sconst "I" + cc_setonmouseleave + iconst 130 + iconst -2147483644 + sconst "event_opbase" + iconst -1 + iconst -1 + iconst -1 + sconst "null" + sconst "null" + sconst "isIiiss" + cc_setonop +LABEL227: + iconst 0 + cc_sethide 1 + jump LABEL246 +LABEL230: + iconst 40 + iload 6 + sconst "I" + cc_setonmouseover + iconst 1 + cc_sethide 1 + iconst 130 + iconst -2147483644 + sconst "event_opbase" + iconst -1 + iconst -1 + iconst -1 + sconst "null" + sconst "null" + sconst "isIiiss" + cc_setonop +LABEL246: + iload 7 + iconst 1 + add + iload 9 + iload 10 + add + istore 9 + istore 7 + jump LABEL97 +LABEL255: + iload 12 + iconst 1 + if_icmpge LABEL259 + jump LABEL263 +LABEL259: + iload 9 + iconst 5 + add + istore 9 +LABEL263: + iload 9 + iload 3 + if_getheight + if_icmpgt LABEL268 + jump LABEL278 +LABEL268: + iconst 0 + iload 9 + iload 3 + if_setscrollsize + iload 4 + iload 3 + iload 3 + if_getscrolly + invoke 72 + jump LABEL286 +LABEL278: + iconst 0 + iconst 0 + iload 3 + if_setscrollsize + iload 4 + iload 3 + iconst 0 + invoke 72 +LABEL286: + return From 7b4e8c2848ad605b3b54cdceb4a915ea47f02a08 Mon Sep 17 00:00:00 2001 From: ThatGamerBlue Date: Fri, 13 Mar 2020 17:50:54 +0000 Subject: [PATCH 17/25] friendicons: add note icon in friends/ignore list Co-authored-by: Adam --- .../main/java/net/runelite/api/ScriptID.java | 32 ++++ .../net/runelite/api/widgets/WidgetID.java | 16 ++ .../net/runelite/api/widgets/WidgetInfo.java | 16 ++ .../friendnotes/FriendNotesConfig.java | 46 +++++ .../friendnotes/FriendNotesPlugin.java | 175 +++++++++++++++++- .../client/plugins/friendnotes/note_icon.png | Bin 0 -> 931 bytes .../src/main/scripts/FriendUpdate.rs2asm | 10 + .../src/main/scripts/IgnoreUpdate.rs2asm | 10 + 8 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesConfig.java create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/friendnotes/note_icon.png diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java index 1fb85b0145..494489fadc 100644 --- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java +++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java @@ -233,4 +233,36 @@ public final class ScriptID */ @ScriptArguments(integer = 2) public static final int TOPLEVEL_RESIZE = 909; + + /** + * Called when the friends list is updated + *
    + *
  • int (WidgetID) Friends list "full container"
  • + *
  • int (WidgetID) Friends list sort by name button
  • + *
  • int (WidgetID) Friends list sort by last world change button
  • + *
  • int (WidgetID) Friends list sort by world button
  • + *
  • int (WidgetID) Friends list legacy sort button
  • + *
  • int (WidgetID) Friends list names container
  • + *
  • int (WidgetID) Friends list scroll bar
  • + *
  • int (WidgetID) Friends list "loading please wait" text
  • + *
  • int (WidgetID) Friends list player previous name holder
  • + *
+ */ + @ScriptArguments(integer = 9) + public static final int FRIENDS_UPDATE = 631; + + /** + * Called when the ignore list is updated + *
    + *
  • int (WidgetID) Ignore list "full container"
  • + *
  • int (WidgetID) Ignore list sort by name button
  • + *
  • int (WidgetID) Ignore list legacy sort button
  • + *
  • int (WidgetID) Ignore list names container
  • + *
  • int (WidgetID) Ignore list scroll bar
  • + *
  • int (WidgetID) Ignore list "loading please wait" text
  • + *
  • int (WidgetID) Ignore list player previous name holder
  • + *
+ */ + @ScriptArguments(integer = 7) + public static final int IGNORE_UPDATE = 630; } 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 859ea90bda..d957b3f8d5 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 @@ -215,11 +215,27 @@ public class WidgetID static class FriendList { static final int TITLE = 3; + static final int FULL_CONTAINER = 5; + static final int SORT_BY_NAME_BUTTON = 7; + static final int SORT_BY_LAST_WORLD_CHANGE_BUTTON = 8; + static final int SORT_BY_WORLD_BUTTON = 9; + static final int LEGACY_SORT_BUTTON = 10; + static final int NAMES_CONTAINER = 11; + static final int SCROLL_BAR = 12; + static final int LOADING_TEXT = 13; + static final int PREVIOUS_NAME_HOLDER = 18; } static class IgnoreList { static final int TITLE = 3; + static final int FULL_CONTAINER = 5; + static final int SORT_BY_NAME_BUTTON = 7; + static final int LEGACY_SORT_BUTTON = 8; + static final int NAMES_CONTAINER = 9; + static final int SCROLL_BAR = 10; + static final int LOADING_TEXT = 11; + static final int PREVIOUS_NAME_HOLDER = 16; } static class ClanChat 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 dec5f89cf6..ea559f8d37 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 @@ -104,8 +104,24 @@ public enum WidgetInfo VOLCANIC_MINE_VENT_C_STATUS(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.VENT_C_STATUS), FRIEND_CHAT_TITLE(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.TITLE), + FRIEND_LIST_FULL_CONTAINER(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.FULL_CONTAINER), + FRIEND_LIST_SORT_BY_NAME_BUTTON(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.SORT_BY_NAME_BUTTON), + FRIEND_LIST_SORT_BY_LAST_WORLD_CHANGE_BUTTON(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.SORT_BY_LAST_WORLD_CHANGE_BUTTON), + FRIEND_LIST_SORT_BY_WORLD_BUTTON(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.SORT_BY_WORLD_BUTTON), + FRIEND_LIST_LEGACY_SORT_BUTTON(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.LEGACY_SORT_BUTTON), + FRIEND_LIST_NAMES_CONTAINER(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.NAMES_CONTAINER), + FRIEND_LIST_SCROLL_BAR(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.SCROLL_BAR), + FRIEND_LIST_LOADING_TEXT(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.LOADING_TEXT), + FRIEND_LIST_PREVIOUS_NAME_HOLDER(WidgetID.FRIENDS_LIST_GROUP_ID, WidgetID.FriendList.PREVIOUS_NAME_HOLDER), IGNORE_TITLE(WidgetID.IGNORE_LIST_GROUP_ID, WidgetID.IgnoreList.TITLE), + IGNORE_FULL_CONTAINER(WidgetID.IGNORE_LIST_GROUP_ID, WidgetID.IgnoreList.FULL_CONTAINER), + IGNORE_SORT_BY_NAME_BUTTON(WidgetID.IGNORE_LIST_GROUP_ID, WidgetID.IgnoreList.SORT_BY_NAME_BUTTON), + IGNORE_LEGACY_SORT_BUTTON(WidgetID.IGNORE_LIST_GROUP_ID, WidgetID.IgnoreList.LEGACY_SORT_BUTTON), + IGNORE_NAMES_CONTAINER(WidgetID.IGNORE_LIST_GROUP_ID, WidgetID.IgnoreList.NAMES_CONTAINER), + IGNORE_SCROLL_BAR(WidgetID.IGNORE_LIST_GROUP_ID, WidgetID.IgnoreList.SCROLL_BAR), + IGNORE_LOADING_TEXT(WidgetID.IGNORE_LIST_GROUP_ID, WidgetID.IgnoreList.LOADING_TEXT), + IGNORE_PREVIOUS_NAME_HOLDER(WidgetID.IGNORE_LIST_GROUP_ID, WidgetID.IgnoreList.PREVIOUS_NAME_HOLDER), EXPLORERS_RING_ALCH_INVENTORY(WidgetID.EXPLORERS_RING_ALCH_GROUP_ID, WidgetID.ExplorersRing.INVENTORY), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesConfig.java new file mode 100644 index 0000000000..abaa5915f7 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020, ThatGamerBlue + * 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 HOLDER 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.friendnotes; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup(FriendNotesPlugin.CONFIG_GROUP) +public interface FriendNotesConfig extends Config +{ + @ConfigItem( + keyName = "showIcons", + name = "Show Icons", + description = "Show icons on friend or ignore list", + position = 1 + ) + default boolean showIcons() + { + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesPlugin.java index ba0d85cff7..94fe830cc1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/friendnotes/FriendNotesPlugin.java @@ -29,29 +29,40 @@ package net.runelite.client.plugins.friendnotes; import com.google.common.base.Strings; import com.google.common.collect.ObjectArrays; +import com.google.inject.Provides; import java.awt.Color; +import java.awt.image.BufferedImage; +import java.util.Arrays; import javax.annotation.Nullable; import javax.inject.Inject; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.Friend; +import net.runelite.api.GameState; import net.runelite.api.Ignore; +import net.runelite.api.IndexedSprite; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; import net.runelite.api.Nameable; +import net.runelite.api.ScriptID; +import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.NameableNameChanged; import net.runelite.api.events.RemovedFriend; +import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.api.widgets.WidgetInfo; +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.chatbox.ChatboxPanelManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; @Slf4j @@ -61,13 +72,15 @@ import net.runelite.client.util.Text; ) public class FriendNotesPlugin extends Plugin { - private static final String CONFIG_GROUP = "friendNotes"; + static final String CONFIG_GROUP = "friendNotes"; private static final int CHARACTER_LIMIT = 128; private static final String KEY_PREFIX = "note_"; private static final String ADD_NOTE = "Add Note"; private static final String EDIT_NOTE = "Edit Note"; private static final String NOTE_PROMPT_FORMAT = "%s's Notes
" + ColorUtil.prependColorTag("(Limit %s Characters)", new Color(0, 0, 170)); + private static final int ICON_WIDTH = 14; + private static final int ICON_HEIGHT = 12; @Inject private Client client; @@ -84,19 +97,74 @@ public class FriendNotesPlugin extends Plugin @Inject private ChatboxPanelManager chatboxPanelManager; + @Inject + private ClientThread clientThread; + + @Inject + private FriendNotesConfig config; + @Getter private HoveredFriend hoveredFriend = null; + private int iconIdx = -1; + private String currentlyLayouting; + + @Provides + private FriendNotesConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(FriendNotesConfig.class); + } + @Override protected void startUp() throws Exception { overlayManager.add(overlay); + clientThread.invoke(this::loadIcon); + if (client.getGameState() == GameState.LOGGED_IN) + { + rebuildFriendsList(); + rebuildIgnoreList(); + } } @Override protected void shutDown() throws Exception { overlayManager.remove(overlay); + if (client.getGameState() == GameState.LOGGED_IN) + { + rebuildFriendsList(); + rebuildIgnoreList(); + } + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGGED_IN) + { + loadIcon(); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!event.getGroup().equals(CONFIG_GROUP)) + { + return; + } + + switch (event.getKey()) + { + case "showIcons": + if (client.getGameState() == GameState.LOGGED_IN) + { + rebuildFriendsList(); + rebuildIgnoreList(); + } + break; + } } /** @@ -112,6 +180,11 @@ public class FriendNotesPlugin extends Plugin { configManager.setConfiguration(CONFIG_GROUP, KEY_PREFIX + displayName, note); } + if (client.getGameState() == GameState.LOGGED_IN) + { + rebuildFriendsList(); + rebuildIgnoreList(); + } } /** @@ -258,4 +331,104 @@ public class FriendNotesPlugin extends Plugin log.debug("Remove friend: '{}'", displayName); setFriendNote(displayName, null); } + + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent event) + { + if (!config.showIcons() || iconIdx == -1) + { + return; + } + + switch (event.getEventName()) + { + case "friend_cc_settext": + case "ignore_cc_settext": + String[] stringStack = client.getStringStack(); + int stringStackSize = client.getStringStackSize(); + final String rsn = stringStack[stringStackSize - 1]; + final String sanitized = Text.toJagexName(Text.removeTags(rsn)); + currentlyLayouting = sanitized; + if (getFriendNote(sanitized) != null) + { + stringStack[stringStackSize - 1] = rsn + " "; + } + break; + case "friend_cc_setposition": + case "ignore_cc_setposition": + if (currentlyLayouting == null || getFriendNote(currentlyLayouting) == null) + { + return; + } + + int[] intStack = client.getIntStack(); + int intStackSize = client.getIntStackSize(); + int xpos = intStack[intStackSize - 4]; + xpos += ICON_WIDTH + 1; + intStack[intStackSize - 4] = xpos; + break; + } + } + + private void rebuildFriendsList() + { + clientThread.invokeLater(() -> + { + log.debug("Rebuilding friends list"); + client.runScript( + ScriptID.FRIENDS_UPDATE, + WidgetInfo.FRIEND_LIST_FULL_CONTAINER.getPackedId(), + WidgetInfo.FRIEND_LIST_SORT_BY_NAME_BUTTON.getPackedId(), + WidgetInfo.FRIEND_LIST_SORT_BY_LAST_WORLD_CHANGE_BUTTON.getPackedId(), + WidgetInfo.FRIEND_LIST_SORT_BY_WORLD_BUTTON.getPackedId(), + WidgetInfo.FRIEND_LIST_LEGACY_SORT_BUTTON.getPackedId(), + WidgetInfo.FRIEND_LIST_NAMES_CONTAINER.getPackedId(), + WidgetInfo.FRIEND_LIST_SCROLL_BAR.getPackedId(), + WidgetInfo.FRIEND_LIST_LOADING_TEXT.getPackedId(), + WidgetInfo.FRIEND_LIST_PREVIOUS_NAME_HOLDER.getPackedId() + ); + }); + } + + private void rebuildIgnoreList() + { + clientThread.invokeLater(() -> + { + log.debug("Rebuilding ignore list"); + client.runScript( + ScriptID.IGNORE_UPDATE, + WidgetInfo.IGNORE_FULL_CONTAINER.getPackedId(), + WidgetInfo.IGNORE_SORT_BY_NAME_BUTTON.getPackedId(), + WidgetInfo.IGNORE_LEGACY_SORT_BUTTON.getPackedId(), + WidgetInfo.IGNORE_NAMES_CONTAINER.getPackedId(), + WidgetInfo.IGNORE_SCROLL_BAR.getPackedId(), + WidgetInfo.IGNORE_LOADING_TEXT.getPackedId(), + WidgetInfo.IGNORE_PREVIOUS_NAME_HOLDER.getPackedId() + ); + }); + } + + private void loadIcon() + { + final IndexedSprite[] modIcons = client.getModIcons(); + if (iconIdx != -1 || modIcons == null) + { + return; + } + + final BufferedImage iconImg = ImageUtil.getResourceStreamFromClass(getClass(), "note_icon.png"); + if (iconImg == null) + { + return; + } + + final BufferedImage resized = ImageUtil.resizeImage(iconImg, ICON_WIDTH, ICON_HEIGHT); + + final IndexedSprite[] newIcons = Arrays.copyOf(modIcons, modIcons.length + 1); + newIcons[newIcons.length - 1] = ImageUtil.getImageIndexedSprite(resized, client); + + iconIdx = newIcons.length - 1; + client.setModIcons(newIcons); + } + } diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/friendnotes/note_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/friendnotes/note_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9b2625aeb7d4cb3b0e7b68ab892f36a70c0c1d5a GIT binary patch literal 931 zcmV;U16=%xP)LliyEUWf;dl=d=e}D5D%Jzgloz8AF015J7$jQa2|V zf{TVM!wWO-%)L^_&2;gGI;wBLsmKD|nF)hC~ww43^Vb2Ta zcww0YF(mp;-aI$Y_ml7QKJSaaspO}R->BZ|td+-sqx@fec+qQ`>le+L?=G0mp78)n#bcF=OzU{#T!pE}v-ZNGla}4qI>vBNSo9lEtF)IPbjs zCfeo}nzltGyo}SC&-EMA#A5fOE>}L|<3Eng%*>txuw;ONn@fCs_g46YlkR-g<9`<0 z);jsA1OeT_!-YlMTaU6W1o_S*NU}^r!xOyN+imabd(9q+%-2jzOuh#o?-~EM^BvW` zXR78?yW7a!h!eOrjZ*IBA(so&{HxnAOiT<^Rb}Gp4Q74~e6TN}p|5WK zG4MrTvFWR&jYROuEb+0QsqLy^NxRRZ)s@JZ?p>&&D9p{xGdwbOdH+)O%bTlYjkXHC zqWV-ld5<3_yWkjJ?<1Hdn1+F2n3R{f`Q+0Q?ml7*+t&5mi}b{DasX$%d0``Iq+UxB7+oNa8ZlO4GZN=r*9E-vEA_$YVR zCy7QYXl`j@`j-H~U`S7;l0$pF@iqi-l9CyHFe@%m!vrtO|K~ zdFZ;3L0a4EJusoq=WS5c0%9=@Ns=C%&d#SXj8=4^)6?@j!^7W)!MuHFLLtPq&1NGz zJDZ)I9Sp<3Fbqu7Bqt|_L_Eo*OYbK~M#f(Ul7}YLv@I4E7D=bm_c;vymjZS(0ciFZa|pHPxSv$CI?Tx2UD1MW|{4m6bk1p#{#IIrkCp z)}g?CvSn(&-EJ$XtE+vfs;Z)5X=x=kI{L#|FsJr5{|O2nU=+0B#-{)P002ovPDHLk FV1jxZ$8Z1u literal 0 HcmV?d00001 diff --git a/runelite-client/src/main/scripts/FriendUpdate.rs2asm b/runelite-client/src/main/scripts/FriendUpdate.rs2asm index e2d838bd66..69cb250b31 100644 --- a/runelite-client/src/main/scripts/FriendUpdate.rs2asm +++ b/runelite-client/src/main/scripts/FriendUpdate.rs2asm @@ -3,6 +3,12 @@ .string_stack_count 0 .int_var_count 16 .string_var_count 2 +; callback "friend_cc_settext" +; Fired just before the client pops the name off the stack +; Modified by the friendnotes plugin to show the icon +; callback "friend_cc_setposition" +; Fired just before the client sets the position of "friend changed their name" icon +; Modified by the friendnotes plugin to offset the name changed icon iload 1 iconst 2 iconst 3 @@ -276,6 +282,8 @@ LABEL218: add istore 10 sload 0 + sconst "friend_cc_settext" + runelite_callback cc_settext iconst 0 iload 13 @@ -356,6 +364,8 @@ LABEL277: add iconst 0 iconst 0 + sconst "friend_cc_setposition" + runelite_callback cc_setposition 1 iconst 1093 cc_setgraphic 1 diff --git a/runelite-client/src/main/scripts/IgnoreUpdate.rs2asm b/runelite-client/src/main/scripts/IgnoreUpdate.rs2asm index c50a07f093..a99a72a2f1 100644 --- a/runelite-client/src/main/scripts/IgnoreUpdate.rs2asm +++ b/runelite-client/src/main/scripts/IgnoreUpdate.rs2asm @@ -3,6 +3,12 @@ .string_stack_count 0 .int_var_count 13 .string_var_count 2 +; callback "ignore_cc_settext" +; Fired just before the client pops the name off the stack +; Modified by the friendnotes plugin to show the icon +; callback "ignore_cc_setposition" +; Fired just before the client sets the position of "ignored person changed their name" icon +; Modified by the friendnotes plugin to offset the name changed icon iload 1 iconst 2 iconst 3 @@ -133,6 +139,8 @@ LABEL101: add istore 8 sload 0 + sconst "ignore_cc_settext" + runelite_callback cc_settext iconst 0 iload 10 @@ -190,6 +198,8 @@ LABEL101: add iconst 0 iconst 0 + sconst "ignore_cc_setposition" + runelite_callback cc_setposition 1 iconst 1093 cc_setgraphic 1 From 24e291fd463c9b5bf6910a116d32c3625b8a3851 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 17 Mar 2020 09:57:21 +1100 Subject: [PATCH 18/25] loottracker: add average per kill to subtitle tooltip --- .../net/runelite/client/plugins/loottracker/LootTrackerBox.java | 1 + 1 file changed, 1 insertion(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java index eda30ffb3a..6e7d08cc97 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java @@ -222,6 +222,7 @@ class LootTrackerBox extends JPanel if (kills > 1) { subTitleLabel.setText("x " + kills); + subTitleLabel.setToolTipText(QuantityFormatter.formatNumber(totalPrice / kills) + " gp (average)"); } validate(); From c1d5e3ae161b6c195f37306a5c67e8eef4904562 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 16 Mar 2020 19:52:15 -0400 Subject: [PATCH 19/25] hiscore panel: autocomplete recent search history Co-authored-by: Daniel --- .../client/plugins/hiscore/HiscorePanel.java | 13 ++++- .../client/plugins/hiscore/HiscorePlugin.java | 23 +-------- .../plugins/hiscore/NameAutocompleter.java | 48 +++++++++++++++---- .../plugins/hiscore/HiscorePanelTest.java | 5 +- 4 files changed, 54 insertions(+), 35 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePanel.java index 4e67a0868c..ca5df48a6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePanel.java @@ -121,6 +121,7 @@ public class HiscorePanel extends PluginPanel private Client client; private final HiscoreConfig config; + private final NameAutocompleter nameAutocompleter; private final IconTextField searchBar; @@ -141,10 +142,11 @@ public class HiscorePanel extends PluginPanel private boolean loading = false; @Inject - public HiscorePanel(HiscoreConfig config) + public HiscorePanel(HiscoreConfig config, NameAutocompleter nameAutocompleter) { super(); this.config = config; + this.nameAutocompleter = nameAutocompleter; // The layout seems to be ignoring the top margin and only gives it // a 2-3 pixel margin, so I set the value to 18 to compensate @@ -295,6 +297,13 @@ public class HiscorePanel extends PluginPanel add(bossPanel, c); c.gridy++; + + addInputKeyListener(nameAutocompleter); + } + + void shutdown() + { + removeInputKeyListener(nameAutocompleter); } @Override @@ -418,6 +427,8 @@ public class HiscorePanel extends PluginPanel searchBar.setEditable(true); loading = false; + nameAutocompleter.addToSearchHistory(result.getPlayer().toLowerCase()); + for (Map.Entry entry : skillLabels.entrySet()) { HiscoreSkill skill = entry.getKey(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java index d2320484db..5ce1d4b9e9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java @@ -41,12 +41,12 @@ import net.runelite.api.Client; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; import net.runelite.api.events.ChatMessage; -import net.runelite.client.events.ConfigChanged; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.PlayerMenuOptionClicked; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.menus.MenuManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -88,9 +88,6 @@ public class HiscorePlugin extends Plugin private NavigationButton navButton; private HiscorePanel hiscorePanel; - @Inject - private NameAutocompleter autocompleter; - @Provides HiscoreConfig provideConfig(ConfigManager configManager) { @@ -117,16 +114,12 @@ public class HiscorePlugin extends Plugin { menuManager.get().addPlayerMenuItem(LOOKUP); } - if (config.autocomplete()) - { - hiscorePanel.addInputKeyListener(autocompleter); - } } @Override protected void shutDown() throws Exception { - hiscorePanel.removeInputKeyListener(autocompleter); + hiscorePanel.shutdown(); clientToolbar.removeNavigation(navButton); if (client != null) @@ -149,18 +142,6 @@ public class HiscorePlugin extends Plugin menuManager.get().addPlayerMenuItem(LOOKUP); } } - - if (event.getKey().equals("autocomplete")) - { - if (config.autocomplete()) - { - hiscorePanel.addInputKeyListener(autocompleter); - } - else - { - hiscorePanel.removeInputKeyListener(autocompleter); - } - } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java index e89cbb2a8d..1cdbaf526e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.hiscore; +import com.google.common.collect.EvictingQueue; import com.google.inject.Inject; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; @@ -32,10 +33,12 @@ import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; import javax.annotation.Nullable; +import javax.inject.Singleton; import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; +import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ClanMemberManager; import net.runelite.api.Client; @@ -45,6 +48,7 @@ import net.runelite.api.NameableContainer; import net.runelite.api.Player; @Slf4j +@Singleton class NameAutocompleter implements KeyListener { /** @@ -57,7 +61,12 @@ class NameAutocompleter implements KeyListener */ private static final Pattern INVALID_CHARS = Pattern.compile("[^a-zA-Z0-9_ -]"); + private static final int MAX_SEARCH_HISTORY = 25; + private final Client client; + private final HiscoreConfig hiscoreConfig; + + private final EvictingQueue searchHistory = EvictingQueue.create(MAX_SEARCH_HISTORY); /** * The name currently being autocompleted. @@ -70,9 +79,10 @@ class NameAutocompleter implements KeyListener private Pattern autocompleteNamePattern; @Inject - private NameAutocompleter(@Nullable Client client) + private NameAutocompleter(@Nullable Client client, HiscoreConfig hiscoreConfig) { this.client = client; + this.hiscoreConfig = hiscoreConfig; } @Override @@ -90,6 +100,11 @@ class NameAutocompleter implements KeyListener @Override public void keyTyped(KeyEvent e) { + if (!hiscoreConfig.autocomplete()) + { + return; + } + final JTextComponent input = (JTextComponent)e.getSource(); final String inputText = input.getText(); @@ -189,17 +204,22 @@ class NameAutocompleter implements KeyListener return false; } - autocompleteName = Optional.empty(); + // Search all previous successful queries + autocompleteName = searchHistory.stream() + .filter(n -> pattern.matcher(n).matches()) + .findFirst(); - // TODO: Search lookup history - - NameableContainer friendContainer = client.getFriendContainer(); - if (friendContainer != null) + // Search friends if previous searches weren't matched + if (!autocompleteName.isPresent()) { - autocompleteName = Arrays.stream(friendContainer.getMembers()) - .map(Nameable::getName) - .filter(n -> pattern.matcher(n).matches()) - .findFirst(); + NameableContainer friendContainer = client.getFriendContainer(); + if (friendContainer != null) + { + autocompleteName = Arrays.stream(friendContainer.getMembers()) + .map(Nameable::getName) + .filter(n -> pattern.matcher(n).matches()) + .findFirst(); + } } // Search clan if a friend wasn't found @@ -241,6 +261,14 @@ class NameAutocompleter implements KeyListener return autocompleteName.isPresent(); } + void addToSearchHistory(@NonNull String name) + { + if (!searchHistory.contains(name)) + { + searchHistory.offer(name); + } + } + private boolean isExpectedNext(JTextComponent input, String nextChar) { String expected; diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/hiscore/HiscorePanelTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/hiscore/HiscorePanelTest.java index 3d5255f088..dfee0deeba 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/hiscore/HiscorePanelTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/hiscore/HiscorePanelTest.java @@ -27,15 +27,14 @@ package net.runelite.client.plugins.hiscore; import static net.runelite.client.plugins.hiscore.HiscorePanel.formatLevel; import static org.junit.Assert.assertEquals; import org.junit.Test; +import static org.mockito.Mockito.mock; public class HiscorePanelTest { @Test public void testConstructor() { - new HiscorePanel(new HiscoreConfig() - { - }); + new HiscorePanel(mock(HiscoreConfig.class), mock(NameAutocompleter.class)); } @Test From 5f5123a9c3258adeb7bdfb146ddaef4c2114a28a Mon Sep 17 00:00:00 2001 From: dekvall Date: Mon, 2 Mar 2020 20:25:23 +0100 Subject: [PATCH 20/25] object indicators: add support for multiple colors --- .../objectindicators/ColorTileObject.java | 42 ++++++++++++++++ .../ObjectIndicatorsConfig.java | 10 ++++ .../ObjectIndicatorsOverlay.java | 16 +++++-- .../ObjectIndicatorsPlugin.java | 48 +++++++++++-------- .../plugins/objectindicators/ObjectPoint.java | 4 +- 5 files changed, 96 insertions(+), 24 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ColorTileObject.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ColorTileObject.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ColorTileObject.java new file mode 100644 index 0000000000..1af342cd20 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ColorTileObject.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, dekvall + * 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.objectindicators; + +import java.awt.Color; +import lombok.RequiredArgsConstructor; +import lombok.Value; +import net.runelite.api.TileObject; + +/** + * Used to denote marked objects and their colors. + * Note: This is not used for serialization of object indicators; see {@link ObjectPoint} + */ +@Value +@RequiredArgsConstructor +class ColorTileObject +{ + private final TileObject tileObject; + private final Color color; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsConfig.java index e7bd35eb58..049269756b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsConfig.java @@ -44,4 +44,14 @@ public interface ObjectIndicatorsConfig extends Config { return Color.YELLOW; } + + @ConfigItem( + keyName = "rememberObjectColors", + name = "Remember color per object", + description = "Color objects using the color from time of marking" + ) + default boolean rememberObjectColors() + { + return false; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsOverlay.java index 21d0a4692d..0e52edf0a4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsOverlay.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.objectindicators; +import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Shape; @@ -60,13 +61,22 @@ class ObjectIndicatorsOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - for (TileObject object : plugin.getObjects()) + for (ColorTileObject colorTileObject : plugin.getObjects()) { + TileObject object = colorTileObject.getTileObject(); + Color color = colorTileObject.getColor(); + if (object.getPlane() != client.getPlane()) { continue; } + if (color == null || !config.rememberObjectColors()) + { + // Fallback to the current config if the object is marked before the addition of multiple colors + color = config.markerColor(); + } + final Shape polygon; Shape polygon2 = null; @@ -95,12 +105,12 @@ class ObjectIndicatorsOverlay extends Overlay if (polygon != null) { - OverlayUtil.renderPolygon(graphics, polygon, config.markerColor()); + OverlayUtil.renderPolygon(graphics, polygon, color); } if (polygon2 != null) { - OverlayUtil.renderPolygon(graphics, polygon2, config.markerColor()); + OverlayUtil.renderPolygon(graphics, polygon2, color); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java index 397b24b29c..1d826d7641 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java @@ -29,6 +29,7 @@ import com.google.common.base.Strings; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.google.inject.Provides; +import java.awt.Color; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Arrays; @@ -91,7 +92,7 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener private final Gson GSON = new Gson(); @Getter(AccessLevel.PACKAGE) - private final List objects = new ArrayList<>(); + private final List objects = new ArrayList<>(); private final Map> points = new HashMap<>(); private boolean hotKeyPressed; @@ -110,6 +111,9 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener @Inject private KeyManager keyManager; + @Inject + private ObjectIndicatorsConfig config; + @Provides ObjectIndicatorsConfig provideConfig(ConfigManager configManager) { @@ -178,54 +182,50 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener WallObject previous = event.getPrevious(); WallObject wallObject = event.getWallObject(); - objects.remove(previous); + objects.removeIf(o -> o.getTileObject() == previous); checkObjectPoints(wallObject); } @Subscribe public void onWallObjectDespawned(WallObjectDespawned event) { - objects.remove(event.getWallObject()); + objects.removeIf(o -> o.getTileObject() == event.getWallObject()); } @Subscribe public void onGameObjectSpawned(GameObjectSpawned event) { - final GameObject eventObject = event.getGameObject(); - checkObjectPoints(eventObject); + checkObjectPoints(event.getGameObject()); } @Subscribe public void onDecorativeObjectSpawned(DecorativeObjectSpawned event) { - final DecorativeObject eventObject = event.getDecorativeObject(); - checkObjectPoints(eventObject); + checkObjectPoints(event.getDecorativeObject()); } @Subscribe public void onGameObjectDespawned(GameObjectDespawned event) { - objects.remove(event.getGameObject()); + objects.removeIf(o -> o.getTileObject() == event.getGameObject()); } @Subscribe public void onDecorativeObjectDespawned(DecorativeObjectDespawned event) { - objects.remove(event.getDecorativeObject()); + objects.removeIf(o -> o.getTileObject() == event.getDecorativeObject()); } @Subscribe - public void onGroundObjectSpawned(GroundObjectSpawned groundObjectSpawned) + public void onGroundObjectSpawned(GroundObjectSpawned event) { - final GroundObject groundObject = groundObjectSpawned.getGroundObject(); - checkObjectPoints(groundObject); + checkObjectPoints(event.getGroundObject()); } @Subscribe - public void onGroundObjectDespawned(GroundObjectDespawned groundObjectDespawned) + public void onGroundObjectDespawned(GroundObjectDespawned event) { - GroundObject groundObject = groundObjectDespawned.getGroundObject(); - objects.remove(groundObject); + objects.removeIf(o -> o.getTileObject() == event.getGroundObject()); } @Subscribe @@ -263,11 +263,17 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener } final Tile tile = client.getScene().getTiles()[client.getPlane()][event.getActionParam0()][event.getActionParam1()]; + final TileObject tileObject = findTileObject(tile, event.getIdentifier()); + + if (tileObject == null) + { + return; + } MenuEntry[] menuEntries = client.getMenuEntries(); menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1); MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); - menuEntry.setOption(objects.contains(findTileObject(tile, event.getIdentifier())) ? UNMARK : MARK); + menuEntry.setOption(objects.stream().anyMatch(o -> o.getTileObject() == tileObject) ? UNMARK : MARK); menuEntry.setTarget(event.getTarget()); menuEntry.setParam0(event.getActionParam0()); menuEntry.setParam1(event.getActionParam1()); @@ -332,7 +338,7 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener if (objectPoint.getName().equals(getObjectComposition(object.getId()).getName())) { log.debug("Marking object {} due to matching {}", object, objectPoint); - objects.add(object); + objects.add(new ColorTileObject(object, objectPoint.getColor())); break; } } @@ -417,17 +423,19 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener { final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation()); final int regionId = worldPoint.getRegionID(); + final Color color = config.markerColor(); final ObjectPoint point = new ObjectPoint( object.getId(), name, regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), - worldPoint.getPlane()); + worldPoint.getPlane(), + color); Set objectPoints = points.computeIfAbsent(regionId, k -> new HashSet<>()); - if (objects.remove(object)) + if (objects.removeIf(o -> o.getTileObject() == object)) { // Find the object point that caused this object to be marked, there are two cases: // 1) object is a multiloc, the name may have changed since marking - match from base id @@ -446,7 +454,7 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener else { objectPoints.add(point); - objects.add(object); + objects.add(new ColorTileObject(object, color)); log.debug("Marking object: {}", point); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectPoint.java index ca8786faa3..6064eb2118 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectPoint.java @@ -25,6 +25,7 @@ package net.runelite.client.plugins.objectindicators; +import java.awt.Color; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -40,4 +41,5 @@ class ObjectPoint private int regionX; private int regionY; private int z; -} \ No newline at end of file + private Color color; +} From ba013c19b61cbcd79b0d977106978c6a7671597c Mon Sep 17 00:00:00 2001 From: Justin Hiltz Date: Tue, 17 Mar 2020 17:19:18 -0300 Subject: [PATCH 21/25] worldmap: Add Prifddinas mining sites (#11018) --- .../runelite/client/plugins/worldmap/MiningSiteLocation.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java index f52ba791bb..405e08488d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java @@ -41,6 +41,7 @@ enum MiningSiteLocation new Rock(3, Ore.COAL), new Rock(3, Ore.MITHRIL), new Rock(2, Ore.ADAMANTITE)), AL_KHARID_MINE_SOUTH(new WorldPoint(3298, 3282, 0), new Rock(2, Ore.IRON), new Rock(2, Ore.GOLD)), ARANDAR(new WorldPoint(2322, 3269, 0), new Rock(8, Ore.LIMESTONE)), + ARANDAR_PRIFDDINAS_MAP(new WorldPoint(3346, 6021, 0), new Rock(8, Ore.LIMESTONE)), ARCEUUS_NORTH(new WorldPoint(1763, 3860, 0), new Rock(1, Ore.DENSE_ESSENCE)), ARCEUUS_SOUTH(new WorldPoint(1763, 3844, 0), new Rock(1, Ore.DENSE_ESSENCE)), ARDOUGNE_SEWERS(new WorldPoint(2670, 9680, 0), new Rock(5, Ore.IRON), new Rock(5, Ore.COAL)), @@ -101,6 +102,7 @@ enum MiningSiteLocation new Rock(9, Ore.CLAY), new Rock(8, Ore.IRON), new Rock(4, Ore.SILVER), new Rock(11, Ore.COAL), new Rock(4, Ore.GOLD), new Rock(4, Ore.MITHRIL), new Rock(3, Ore.ADAMANTITE)), GWENITH(new WorldPoint(2163, 3415, 0), new Rock(10, Ore.GOLD)), + GWENITH_PRIFDDINAS_MAP(new WorldPoint(3187, 6167, 0), new Rock(10, Ore.GOLD)), HEROES_GUILD_EAST_BOTTOM(new WorldPoint(2939, 9898, 0), new Rock(3, Ore.COAL), new Rock(2, Ore.RUNITE)), HEROES_GUILD_EAST_TOP(new WorldPoint(2940, 9884, 0), new Rock(5, Ore.COAL)), HEROES_GUILD_WEST_BOTTOM(new WorldPoint(2921, 9904, 0), new Rock(3, Ore.COAL)), From 770f35aceb196245eee1061f1d8a016092173733 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 17 Mar 2020 16:03:34 -0400 Subject: [PATCH 22/25] checkstyle: enforce no whitespace at end of line --- checkstyle.xml | 5 +++++ .../client/plugins/grounditems/GroundItemsConfig.java | 6 +++--- .../client/plugins/itemprices/ItemPricesOverlay.java | 6 +++--- .../plugins/menuentryswapper/MenuEntrySwapperConfig.java | 2 +- .../src/main/java/net/runelite/client/util/LinkBrowser.java | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/checkstyle.xml b/checkstyle.xml index e8669a742c..5c8832b782 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -40,6 +40,11 @@ + + + + + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java index f8752f0d6b..2e1a00ce04 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -124,9 +124,9 @@ public interface GroundItemsConfig extends Config description = "Configures whether or not to highlight tiles containing ground items", position = 6 ) - default boolean highlightTiles() - { - return false; + default boolean highlightTiles() + { + return false; } @ConfigItem( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java index b0605cb684..6b4cefddd0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemprices/ItemPricesOverlay.java @@ -152,9 +152,9 @@ class ItemPricesOverlay extends Overlay ItemContainer container = null; // Inventory item - if (widgetId == INVENTORY_ITEM_WIDGETID || - widgetId == BANK_INVENTORY_ITEM_WIDGETID || - widgetId == EXPLORERS_RING_ITEM_WIDGETID || + if (widgetId == INVENTORY_ITEM_WIDGETID || + widgetId == BANK_INVENTORY_ITEM_WIDGETID || + widgetId == EXPLORERS_RING_ITEM_WIDGETID || widgetId == SEED_VAULT_INVENTORY_ITEM_WIDGETID) { container = client.getItemContainer(InventoryID.INVENTORY); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java index 1e81d1d338..bbcedfca70 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java @@ -417,7 +417,7 @@ public interface MenuEntrySwapperConfig extends Config name = "Essence Mine Teleport", description = "Swaps Talk-To with Teleport for NPCs which teleport you to the essence mine" ) - default boolean swapEssenceMineTeleport() + default boolean swapEssenceMineTeleport() { return false; } diff --git a/runelite-client/src/main/java/net/runelite/client/util/LinkBrowser.java b/runelite-client/src/main/java/net/runelite/client/util/LinkBrowser.java index f4bc491571..e8965029c1 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/LinkBrowser.java +++ b/runelite-client/src/main/java/net/runelite/client/util/LinkBrowser.java @@ -52,7 +52,7 @@ public class LinkBrowser */ public static void browse(final String url) { - new Thread(() -> + new Thread(() -> { if (Strings.isNullOrEmpty(url)) { From 32b98965fe82c6cec5dfbc95c252bf107c681378 Mon Sep 17 00:00:00 2001 From: dekvall Date: Sun, 23 Feb 2020 23:27:33 +0100 Subject: [PATCH 23/25] drift net fishing: add plugin This will add a plugin which shows the status of your nets and highlights any fish you haven't tagged. --- .../main/java/net/runelite/api/Varbits.java | 30 +- .../client/plugins/driftnet/DriftNet.java | 49 +++ .../plugins/driftnet/DriftNetConfig.java | 97 ++++++ .../plugins/driftnet/DriftNetOverlay.java | 104 ++++++ .../plugins/driftnet/DriftNetPlugin.java | 298 ++++++++++++++++++ .../plugins/driftnet/DriftNetStatus.java | 59 ++++ 6 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNet.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetConfig.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetOverlay.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetPlugin.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetStatus.java diff --git a/runelite-api/src/main/java/net/runelite/api/Varbits.java b/runelite-api/src/main/java/net/runelite/api/Varbits.java index c221891fa0..bea1e9b830 100644 --- a/runelite-api/src/main/java/net/runelite/api/Varbits.java +++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java @@ -458,7 +458,35 @@ public enum Varbits * The varbit that stores the oxygen percentage for player */ OXYGEN_LEVEL(5811), - + + /** + * Drift net status + * + * Expected values + * 0 = Unset + * 1 = Set up + * 2 = Caught some fish + * 3 = Full + */ + NORTH_NET_STATUS(5812), + SOUTH_NET_STATUS(5814), + + /** + * Drift net catch count + */ + NORTH_NET_CATCH_COUNT(5813), + SOUTH_NET_CATCH_COUNT(5815), + + /** + * Drift net collect interface + * + * Expected values: + * 0 = Not open + * 1 = North interface open + * 2 = South interface open + */ + DRIFT_NET_COLLECT(5933), + /** * Corp beast damage */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNet.java b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNet.java new file mode 100644 index 0000000000..8a5dfdfeeb --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNet.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, dekvall + * 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 HOLDER 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.driftnet; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import net.runelite.api.GameObject; +import net.runelite.api.Varbits; + +@Data +@RequiredArgsConstructor +class DriftNet +{ + private final int objectId; + private final Varbits statusVarbit; + private final Varbits countVarbit; + + private GameObject net; + private DriftNetStatus status; + private int count; + + String getFormattedCountText() + { + return status != DriftNetStatus.UNSET ? count + "/10" : ""; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetConfig.java new file mode 100644 index 0000000000..e5f9756de8 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetConfig.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020, dekvall + * 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 HOLDER 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.driftnet; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Range; +import net.runelite.client.config.Units; + +@ConfigGroup(DriftNetPlugin.CONFIG_GROUP) +public interface DriftNetConfig extends Config +{ + @ConfigItem( + position = 1, + keyName = "showNetStatus", + name = "Show net status", + description = "Show net status and fish count" + ) + default boolean showNetStatus() + { + return true; + } + + @ConfigItem( + position = 2, + keyName = "countColor", + name = "Fish count color", + description = "Color of the fish count text" + ) + default Color countColor() + { + return Color.WHITE; + } + + @ConfigItem( + position = 3, + keyName = "highlightUntaggedFish", + name = "Highlight untagged fish", + description = "Highlight the untagged fish" + ) + default boolean highlightUntaggedFish() + { + return true; + } + + @ConfigItem( + position = 4, + keyName = "timeoutDelay", + name = "Tagged timeout", + description = "Time required for a tag to expire" + ) + @Range( + min = 1, + max = 60 + ) + @Units(Units.TICKS) + default int timeoutDelay() + { + return 10; + } + + @ConfigItem( + keyName = "untaggedFishColor", + name = "Untagged fish color", + description = "Color of untagged fish", + position = 5 + ) + default Color untaggedFishColor() + { + return Color.CYAN; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetOverlay.java new file mode 100644 index 0000000000..d01c88344c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetOverlay.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020, dekvall + * 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.driftnet; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Shape; +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.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; + +class DriftNetOverlay extends Overlay +{ + private final DriftNetConfig config; + private final DriftNetPlugin plugin; + + @Inject + private DriftNetOverlay(DriftNetConfig config, DriftNetPlugin plugin) + { + this.config = config; + this.plugin = plugin; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.LOW); + setLayer(OverlayLayer.ABOVE_SCENE); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.isInDriftNetArea()) + { + return null; + } + + if (config.highlightUntaggedFish()) + { + renderFish(graphics); + } + if (config.showNetStatus()) + { + renderNets(graphics); + } + + return null; + } + + private void renderFish(Graphics2D graphics) + { + for (NPC fish : plugin.getFish()) + { + if (!plugin.getTaggedFish().containsKey(fish)) + { + OverlayUtil.renderActorOverlay(graphics, fish, "", config.untaggedFishColor()); + } + } + } + + private void renderNets(Graphics2D graphics) + { + for (DriftNet net : plugin.getNETS()) + { + final Shape polygon = net.getNet().getConvexHull(); + + if (polygon != null) + { + OverlayUtil.renderPolygon(graphics, polygon, net.getStatus().getColor()); + } + + String text = net.getFormattedCountText(); + Point textLocation = net.getNet().getCanvasTextLocation(graphics, text, 0); + if (textLocation != null) + { + OverlayUtil.renderTextLocation(graphics, textLocation, text, config.countColor()); + } + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetPlugin.java new file mode 100644 index 0000000000..8dd6ff16b9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetPlugin.java @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2020, dekvall + * 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 HOLDER 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.driftnet; + +import com.google.common.collect.ImmutableList; +import com.google.inject.Provides; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.inject.Inject; +import lombok.Getter; +import net.runelite.api.Actor; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import net.runelite.api.GameState; +import net.runelite.api.NPC; +import net.runelite.api.NpcID; +import net.runelite.api.NullObjectID; +import net.runelite.api.Player; +import net.runelite.api.Varbits; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameObjectDespawned; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.InteractingChanged; +import net.runelite.api.events.NpcDespawned; +import net.runelite.api.events.NpcSpawned; +import net.runelite.api.events.VarbitChanged; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Drift Net", + description = "Display information about drift nets", + tags = {"hunter", "fishing", "drift", "net"}, + enabledByDefault = false +) +public class DriftNetPlugin extends Plugin +{ + static final String CONFIG_GROUP = "driftnet"; + private static final int UNDERWATER_REGION = 15008; + private static final String CHAT_PRODDING_FISH = "You prod at the shoal of fish to scare it."; + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private DriftNetConfig config; + + @Inject + private OverlayManager overlayManager; + + @Inject + private DriftNetOverlay overlay; + + @Getter + private Set fish = new HashSet<>(); + @Getter + private Map taggedFish = new HashMap<>(); + @Getter + private final List NETS = ImmutableList.of( + new DriftNet(NullObjectID.NULL_31433, Varbits.NORTH_NET_STATUS, Varbits.NORTH_NET_CATCH_COUNT), + new DriftNet(NullObjectID.NULL_31434, Varbits.SOUTH_NET_STATUS, Varbits.SOUTH_NET_CATCH_COUNT)); + + @Getter + private boolean inDriftNetArea; + private boolean armInteraction; + + @Provides + DriftNetConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(DriftNetConfig.class); + } + + @Override + protected void startUp() + { + overlayManager.add(overlay); + + if (client.getGameState() == GameState.LOGGED_IN) + { + clientThread.invokeLater(() -> + { + inDriftNetArea = checkArea(); + updateDriftNetVarbits(); + }); + } + } + + @Override + protected void shutDown() + { + overlayManager.remove(overlay); + reset(); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + switch (event.getGameState()) + { + case LOGIN_SCREEN: + case HOPPING: + case LOADING: + reset(); + break; + case LOGGED_IN: + inDriftNetArea = checkArea(); + updateDriftNetVarbits(); + break; + } + } + + private void reset() + { + fish.clear(); + taggedFish.clear(); + armInteraction = false; + inDriftNetArea = false; + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + updateDriftNetVarbits(); + } + + private void updateDriftNetVarbits() + { + if (!inDriftNetArea) + { + return; + } + + for (DriftNet net : NETS) + { + DriftNetStatus status = DriftNetStatus.of(client.getVar(net.getStatusVarbit())); + int count = client.getVar(net.getCountVarbit()); + + net.setStatus(status); + net.setCount(count); + } + + // When you collect any loot, all tags become invalidated + if (client.getVar(Varbits.DRIFT_NET_COLLECT) != 0) + { + taggedFish.clear(); + } + } + + @Subscribe + public void onInteractingChanged(InteractingChanged event) + { + if (armInteraction + && event.getSource() == client.getLocalPlayer() + && event.getTarget() instanceof NPC + && ((NPC) event.getTarget()).getId() == NpcID.FISH_SHOAL) + { + tagFish(event.getTarget()); + armInteraction = false; + } + } + + @Subscribe + public void onGameTick(GameTick tick) + { + if (!inDriftNetArea) + { + return; + } + + final int currentTickCount = client.getTickCount(); + taggedFish.entrySet().removeIf(entry -> entry.getValue() + config.timeoutDelay() < currentTickCount); + + armInteraction = false; + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (!inDriftNetArea) + { + return; + } + + if (event.getType() == ChatMessageType.SPAM && event.getMessage().equals(CHAT_PRODDING_FISH)) + { + Actor target = client.getLocalPlayer().getInteracting(); + + if (target instanceof NPC && ((NPC) target).getId() == NpcID.FISH_SHOAL) + { + tagFish(target); + } + else + { + // If the fish is on an adjacent tile, the interaction change happens after + // the chat message is sent, so we arm it + armInteraction = true; + } + } + } + + private void tagFish(Actor fish) + { + NPC fishTarget = (NPC) fish; + taggedFish.put(fishTarget, client.getTickCount()); + } + + @Subscribe + public void onNpcSpawned(NpcSpawned event) + { + final NPC npc = event.getNpc(); + if (npc.getId() == NpcID.FISH_SHOAL) + { + fish.add(npc); + } + } + + @Subscribe + public void onNpcDespawned(NpcDespawned event) + { + final NPC npc = event.getNpc(); + fish.remove(npc); + } + + @Subscribe + public void onGameObjectSpawned(GameObjectSpawned event) + { + GameObject object = event.getGameObject(); + for (DriftNet net : NETS) + { + if (net.getObjectId() == object.getId()) + { + net.setNet(object); + } + } + } + + @Subscribe + public void onGameObjectDespawned(GameObjectDespawned event) + { + GameObject object = event.getGameObject(); + for (DriftNet net : NETS) + { + if (net.getObjectId() == object.getId()) + { + net.setNet(null); + } + } + } + + private boolean checkArea() + { + final Player localPlayer = client.getLocalPlayer(); + if (localPlayer == null || !client.isInInstancedRegion()) + { + return false; + } + + final WorldPoint point = WorldPoint.fromLocalInstance(client, localPlayer.getLocalLocation()); + return point.getRegionID() == UNDERWATER_REGION; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetStatus.java b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetStatus.java new file mode 100644 index 0000000000..e6f7d5699e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/driftnet/DriftNetStatus.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, dekvall + * 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 HOLDER 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.driftnet; + +import java.awt.Color; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +enum DriftNetStatus +{ + UNSET(Color.YELLOW), + SET(Color.GREEN), + CATCH(Color.GREEN), + FULL(Color.RED); + + private final Color color; + + static DriftNetStatus of(int varbitValue) + { + switch (varbitValue) + { + case 0: + return UNSET; + case 1: + return SET; + case 2: + return CATCH; + case 3: + return FULL; + default: + return null; + } + } +} From 9ac4592a63e962530f59b8984edfb5b59551bba4 Mon Sep 17 00:00:00 2001 From: dekvall Date: Fri, 13 Mar 2020 02:20:21 +0100 Subject: [PATCH 24/25] menu entry swapper: swap nets on annette --- .../menuentryswapper/MenuEntrySwapperConfig.java | 10 ++++++++++ .../menuentryswapper/MenuEntrySwapperPlugin.java | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java index bbcedfca70..dd775dfc70 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java @@ -421,4 +421,14 @@ public interface MenuEntrySwapperConfig extends Config { return false; } + + @ConfigItem( + keyName = "swapNets", + name = "Nets", + description = "Swap Talk-to with Nets on Annette" + ) + default boolean swapNets() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java index 903fef7ec3..83e1a7853e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java @@ -471,6 +471,11 @@ public class MenuEntrySwapperPlugin extends Plugin swap("help", option, target, index); } + if (config.swapNets()) + { + swap("nets", option, target, index); + } + if (config.swapDarkMage()) { swap("repairs", option, target, index); From 84a23cb59d94c0382d777e9af430aa87f4b434cf Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 17 Mar 2020 17:34:46 -0400 Subject: [PATCH 25/25] skillcalculator: Don't clear fields when re-loading current skill Previously, clicking on the active calculator's skill would reset the goal level and experience text input fields. This commit prevents that reset when selecting the already-active skill, and only resets them when viewing a different skill's calculator. --- .../skillcalculator/SkillCalculator.java | 81 ++++++++++--------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java index e6410eb712..8b0c10c654 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java @@ -74,6 +74,7 @@ class SkillCalculator extends JPanel private final IconTextField searchBar = new IconTextField(); private SkillData skillData; + private Skill currentSkill; private int currentLevel = 1; private int currentXP = Experience.getXpForLevel(currentLevel); private int targetLevel = currentLevel + 1; @@ -123,48 +124,54 @@ class SkillCalculator extends JPanel void openCalculator(CalculatorType calculatorType) { - // Load the skill data. - skillData = cacheSkillData.getSkillData(calculatorType.getDataFile()); - - // Reset the XP factor, removing bonuses. - xpFactor = 1.0f; - // Update internal skill/XP values. currentXP = client.getSkillExperience(calculatorType.getSkill()); currentLevel = Experience.getLevelForXp(currentXP); - VarPlayer endGoalVarp = endGoalVarpForSkill(calculatorType.getSkill()); - int endGoal = client.getVar(endGoalVarp); - if (endGoal != -1) + + if (currentSkill != calculatorType.getSkill()) { - targetLevel = Experience.getLevelForXp(endGoal); - targetXP = endGoal; + currentSkill = calculatorType.getSkill(); + + // Load the skill data. + skillData = cacheSkillData.getSkillData(calculatorType.getDataFile()); + + // Reset the XP factor, removing bonuses. + xpFactor = 1.0f; + + VarPlayer endGoalVarp = endGoalVarpForSkill(calculatorType.getSkill()); + int endGoal = client.getVar(endGoalVarp); + if (endGoal != -1) + { + targetLevel = Experience.getLevelForXp(endGoal); + targetXP = endGoal; + } + else + { + targetLevel = enforceSkillBounds(currentLevel + 1); + targetXP = Experience.getXpForLevel(targetLevel); + } + + // Remove all components (action slots) from this panel. + removeAll(); + + // Clear the search bar + searchBar.setText(null); + + // Clear the combined action slots + clearCombinedSlots(); + + // Add in checkboxes for available skill bonuses. + renderBonusOptions(); + + // Add the combined action slot. + add(combinedActionSlot); + + // Add the search bar + add(searchBar); + + // Create action slots for the skill actions. + renderActionSlots(); } - else - { - targetLevel = enforceSkillBounds(currentLevel + 1); - targetXP = Experience.getXpForLevel(targetLevel); - } - - // Remove all components (action slots) from this panel. - removeAll(); - - // Clear the search bar - searchBar.setText(null); - - // Clear the combined action slots - clearCombinedSlots(); - - // Add in checkboxes for available skill bonuses. - renderBonusOptions(); - - // Add the combined action slot. - add(combinedActionSlot); - - // Add the search bar - add(searchBar); - - // Create action slots for the skill actions. - renderActionSlots(); // Update the input fields. updateInputFields();