From 81a8b44d5558deafddf6608cd378c08a837ace98 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Thu, 29 Aug 2019 15:28:37 +0100 Subject: [PATCH 1/5] runecraft: move rift update function to plugin --- .../plugins/runecraft/AbyssOverlay.java | 73 +------------------ .../plugins/runecraft/RunecraftPlugin.java | 65 ++++++++++++++++- 2 files changed, 64 insertions(+), 74 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java index 89954b6468..e945efbc28 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java @@ -27,19 +27,6 @@ package net.runelite.client.plugins.runecraft; import java.awt.Color; import java.awt.Polygon; import java.awt.geom.Area; -import static net.runelite.client.plugins.runecraft.AbyssRifts.AIR_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.BLOOD_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.BODY_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.CHAOS_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.COSMIC_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.DEATH_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.EARTH_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.FIRE_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.LAW_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.MIND_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.NATURE_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.SOUL_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.WATER_RIFT; import com.google.inject.Inject; import java.awt.Dimension; import java.awt.Graphics2D; @@ -63,7 +50,6 @@ class AbyssOverlay extends Overlay { private static final Dimension IMAGE_SIZE = new Dimension(15, 14); - private final Set rifts = new HashSet<>(); private final Map abyssIcons = new HashMap<>(); private final Client client; @@ -127,7 +113,7 @@ class AbyssOverlay extends Overlay private void renderRifts(Graphics2D graphics, DecorativeObject object) { AbyssRifts rift = AbyssRifts.getRift(object.getId()); - if (rift == null || !rifts.contains(rift)) + if (rift == null || !plugin.getRifts().contains(rift)) { return; } @@ -181,61 +167,4 @@ class AbyssOverlay extends Overlay abyssIcons.put(rift, resizedImage); return resizedImage; } - - public void updateConfig() - { - rifts.clear(); - if (config.showAir()) - { - rifts.add(AIR_RIFT); - } - if (config.showBlood()) - { - rifts.add(BLOOD_RIFT); - } - if (config.showBody()) - { - rifts.add(BODY_RIFT); - } - if (config.showChaos()) - { - rifts.add(CHAOS_RIFT); - } - if (config.showCosmic()) - { - rifts.add(COSMIC_RIFT); - } - if (config.showDeath()) - { - rifts.add(DEATH_RIFT); - } - if (config.showEarth()) - { - rifts.add(EARTH_RIFT); - } - if (config.showFire()) - { - rifts.add(FIRE_RIFT); - } - if (config.showLaw()) - { - rifts.add(LAW_RIFT); - } - if (config.showMind()) - { - rifts.add(MIND_RIFT); - } - if (config.showNature()) - { - rifts.add(NATURE_RIFT); - } - if (config.showSoul()) - { - rifts.add(SOUL_RIFT); - } - if (config.showWater()) - { - rifts.add(WATER_RIFT); - } - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java index ca71c687ef..6fd3d9668c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java @@ -55,6 +55,7 @@ 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 static net.runelite.client.plugins.runecraft.AbyssRifts.*; import net.runelite.client.ui.overlay.OverlayManager; @PluginDescriptor( @@ -75,6 +76,9 @@ public class RunecraftPlugin extends Plugin @Getter(AccessLevel.PACKAGE) private final Set abyssObjects = new HashSet<>(); + @Getter(AccessLevel.PACKAGE) + private final Set rifts = new HashSet<>(); + @Getter(AccessLevel.PACKAGE) private boolean degradedPouchInInventory; @@ -106,7 +110,7 @@ public class RunecraftPlugin extends Plugin protected void startUp() throws Exception { overlayManager.add(abyssOverlay); - abyssOverlay.updateConfig(); + updateRifts(); } @Override @@ -123,7 +127,7 @@ public class RunecraftPlugin extends Plugin { if (event.getGroup().equals("runecraft")) { - abyssOverlay.updateConfig(); + updateRifts(); } } @@ -209,4 +213,61 @@ public class RunecraftPlugin extends Plugin darkMage = null; } } + + private void updateRifts() + { + rifts.clear(); + if (config.showAir()) + { + rifts.add(AIR_RIFT); + } + if (config.showBlood()) + { + rifts.add(BLOOD_RIFT); + } + if (config.showBody()) + { + rifts.add(BODY_RIFT); + } + if (config.showChaos()) + { + rifts.add(CHAOS_RIFT); + } + if (config.showCosmic()) + { + rifts.add(COSMIC_RIFT); + } + if (config.showDeath()) + { + rifts.add(DEATH_RIFT); + } + if (config.showEarth()) + { + rifts.add(EARTH_RIFT); + } + if (config.showFire()) + { + rifts.add(FIRE_RIFT); + } + if (config.showLaw()) + { + rifts.add(LAW_RIFT); + } + if (config.showMind()) + { + rifts.add(MIND_RIFT); + } + if (config.showNature()) + { + rifts.add(NATURE_RIFT); + } + if (config.showSoul()) + { + rifts.add(SOUL_RIFT); + } + if (config.showWater()) + { + rifts.add(WATER_RIFT); + } + } } From a60fdc1a111051c6338be4ba3f12ecdc2b3e99a8 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Thu, 29 Aug 2019 15:31:50 +0100 Subject: [PATCH 2/5] runecraft: move minimap code to its own overlay --- .../runecraft/AbyssMinimapOverlay.java | 109 ++++++++++++++++++ .../plugins/runecraft/AbyssOverlay.java | 76 +++--------- .../plugins/runecraft/RunecraftPlugin.java | 5 + 3 files changed, 129 insertions(+), 61 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssMinimapOverlay.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssMinimapOverlay.java new file mode 100644 index 0000000000..901fe5f805 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssMinimapOverlay.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019 Hydrox6 + * 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.runecraft; + +import com.google.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.DecorativeObject; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; + +class AbyssMinimapOverlay extends Overlay +{ + private static final Dimension IMAGE_SIZE = new Dimension(15, 14); + + private final Map abyssIcons = new HashMap<>(); + private final Client client; + private final RunecraftPlugin plugin; + private final RunecraftConfig config; + private final ItemManager itemManager; + + @Inject + AbyssMinimapOverlay(Client client, RunecraftPlugin plugin, RunecraftConfig config, ItemManager itemManager) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_WIDGETS); + this.client = client; + this.plugin = plugin; + this.config = config; + this.itemManager = itemManager; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!config.showRifts()) + { + return null; + } + + for (DecorativeObject object : plugin.getAbyssObjects()) + { + AbyssRifts rift = AbyssRifts.getRift(object.getId()); + if (rift == null || !plugin.getRifts().contains(rift)) + { + continue; + } + + BufferedImage image = getImage(rift); + Point miniMapImage = Perspective.getMiniMapImageLocation(client, object.getLocalLocation(), image); + + if (miniMapImage != null) + { + graphics.drawImage(image, miniMapImage.getX(), miniMapImage.getY(), null); + } + } + + return null; + } + + private BufferedImage getImage(AbyssRifts rift) + { + BufferedImage image = abyssIcons.get(rift); + if (image != null) + { + return image; + } + + // Since item image is too big, we must resize it first. + image = itemManager.getImage(rift.getItemId()); + BufferedImage resizedImage = new BufferedImage(IMAGE_SIZE.width, IMAGE_SIZE.height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = resizedImage.createGraphics(); + g.drawImage(image, 0, 0, IMAGE_SIZE.width, IMAGE_SIZE.height, null); + g.dispose(); + + abyssIcons.put(rift, resizedImage); + return resizedImage; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java index e945efbc28..b4d3df3e18 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java @@ -30,17 +30,10 @@ import java.awt.geom.Area; import com.google.inject.Inject; import java.awt.Dimension; import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; import net.runelite.api.Client; import net.runelite.api.DecorativeObject; import net.runelite.api.NPC; -import net.runelite.api.Perspective; import net.runelite.api.Point; -import net.runelite.client.game.ItemManager; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; @@ -48,17 +41,10 @@ import net.runelite.client.ui.overlay.OverlayUtil; class AbyssOverlay extends Overlay { - private static final Dimension IMAGE_SIZE = new Dimension(15, 14); - - private final Map abyssIcons = new HashMap<>(); - private final Client client; private final RunecraftPlugin plugin; private final RunecraftConfig config; - @Inject - private ItemManager itemManager; - @Inject AbyssOverlay(Client client, RunecraftPlugin plugin, RunecraftConfig config) { @@ -72,11 +58,11 @@ class AbyssOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - if (config.showRifts()) + if (config.showRifts() && config.showClickBox()) { for (DecorativeObject object : plugin.getAbyssObjects()) { - renderRifts(graphics, object); + renderRift(graphics, object); } } @@ -110,7 +96,7 @@ class AbyssOverlay extends Overlay OverlayUtil.renderPolygon(graphics, tilePoly, Color.green); } - private void renderRifts(Graphics2D graphics, DecorativeObject object) + private void renderRift(Graphics2D graphics, DecorativeObject object) { AbyssRifts rift = AbyssRifts.getRift(object.getId()); if (rift == null || !plugin.getRifts().contains(rift)) @@ -118,53 +104,21 @@ class AbyssOverlay extends Overlay return; } - if (config.showClickBox()) + Point mousePosition = client.getMouseCanvasPosition(); + Area objectClickbox = object.getClickbox(); + if (objectClickbox != null) { - //Draw clickbox - Point mousePosition = client.getMouseCanvasPosition(); - Area objectClickbox = object.getClickbox(); - if (objectClickbox != null) + if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) { - if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) - { - graphics.setColor(Color.MAGENTA.darker()); - } - else - { - graphics.setColor(Color.MAGENTA); - } - graphics.draw(objectClickbox); - graphics.setColor(new Color(255, 0, 255, 20)); - graphics.fill(objectClickbox); + graphics.setColor(Color.MAGENTA.darker()); } + else + { + graphics.setColor(Color.MAGENTA); + } + graphics.draw(objectClickbox); + graphics.setColor(new Color(255, 0, 255, 20)); + graphics.fill(objectClickbox); } - - //Draw minimap - BufferedImage image = getImage(rift); - Point miniMapImage = Perspective.getMiniMapImageLocation(client, object.getLocalLocation(), image); - - if (miniMapImage != null) - { - graphics.drawImage(image, miniMapImage.getX(), miniMapImage.getY(), null); - } - } - - public BufferedImage getImage(AbyssRifts rift) - { - BufferedImage image = abyssIcons.get(rift); - if (image != null) - { - return image; - } - - // Since item image is too big, we must resize it first. - image = itemManager.getImage(rift.getItemId()); - BufferedImage resizedImage = new BufferedImage(IMAGE_SIZE.width, IMAGE_SIZE.height, BufferedImage.TYPE_INT_ARGB); - Graphics2D g = resizedImage.createGraphics(); - g.drawImage(image, 0, 0, IMAGE_SIZE.width, IMAGE_SIZE.height, null); - g.dispose(); - - abyssIcons.put(rift, resizedImage); - return resizedImage; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java index 6fd3d9668c..89d9c18c1f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java @@ -94,6 +94,9 @@ public class RunecraftPlugin extends Plugin @Inject private AbyssOverlay abyssOverlay; + @Inject + private AbyssMinimapOverlay abyssMinimapOverlay; + @Inject private RunecraftConfig config; @@ -110,6 +113,7 @@ public class RunecraftPlugin extends Plugin protected void startUp() throws Exception { overlayManager.add(abyssOverlay); + overlayManager.add(abyssMinimapOverlay); updateRifts(); } @@ -117,6 +121,7 @@ public class RunecraftPlugin extends Plugin protected void shutDown() throws Exception { overlayManager.remove(abyssOverlay); + overlayManager.remove(abyssMinimapOverlay); abyssObjects.clear(); darkMage = null; degradedPouchInInventory = false; From 58c5017ae91fcde536a141e74f4eb405dea50b5b Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 4 Sep 2019 15:25:33 -0400 Subject: [PATCH 3/5] chat notifications: fix matching messages with color --- .../ChatNotificationsPlugin.java | 81 +++++++++++++++++- .../ChatNotificationsPluginTest.java | 82 +++++++++++++++++++ 2 files changed, 161 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java index 874a446a34..140aa3eef7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java @@ -25,6 +25,7 @@ */ package net.runelite.client.plugins.chatnotifications; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.inject.Provides; import java.util.List; @@ -115,7 +116,7 @@ public class ChatNotificationsPlugin extends Plugin List items = Text.fromCSV(config.highlightWordsString()); String joined = items.stream() .map(Text::escapeJagex) // we compare these strings to the raw Jagex ones - .map(Pattern::quote) + .map(this::quoteAndIgnoreColor) // regex escape and ignore nested colors in the target message .collect(Collectors.joining("|")); // To match \b doesn't work due to <> not being in \w, // so match \b or \s @@ -184,7 +185,26 @@ public class ChatNotificationsPlugin extends Plugin while (matcher.find()) { String value = matcher.group(); - matcher.appendReplacement(stringBuffer, "" + value + ""); + + // Determine the ending color by: + // 1) use the color from value if it has one + // 2) use the last color from stringBuffer + + // To do #2 we just search for the last col tag after calling appendReplacement + String endColor = getLastColor(value); + + // Strip color tags from the highlighted region so that it remains highlighted correctly + value = stripColor(value); + + matcher.appendReplacement(stringBuffer, "' + value); + + if (endColor == null) + { + endColor = getLastColor(stringBuffer.toString()); + } + + // Append end color + stringBuffer.append(endColor == null ? "" : endColor); + update = true; found = true; } @@ -228,4 +248,61 @@ public class ChatNotificationsPlugin extends Plugin String notification = stringBuilder.toString(); notifier.notify(notification); } + + private String quoteAndIgnoreColor(String str) + { + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = 0; i < str.length(); ++i) + { + char c = str.charAt(i); + stringBuilder.append(Pattern.quote(String.valueOf(c))); + stringBuilder.append("(?:]*?>)?"); + } + + return stringBuilder.toString(); + } + + /** + * Get the last color tag from a string, or null if there was none + * + * @param str + * @return + */ + private static String getLastColor(String str) + { + int colIdx = str.lastIndexOf(""); + + if (colEndIdx > colIdx) + { + // ends in a which resets the color to normal + return ""; + } + + if (colIdx == -1) + { + return null; // no color + } + + int closeIdx = str.indexOf('>', colIdx); + if (closeIdx == -1) + { + return null; // unclosed col tag + } + + return str.substring(colIdx, closeIdx + 1); // include the > + } + + /** + * Strip color tags from a string. + * + * @param str + * @return + */ + @VisibleForTesting + static String stripColor(String str) + { + return str.replaceAll("(|)", ""); + } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java index ffa54ccbae..5eda571f9a 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java @@ -131,6 +131,82 @@ public class ChatNotificationsPluginTest verify(messageNode).setValue("foo test. bar"); } + @Test + public void testColor() + { + when(config.highlightWordsString()).thenReturn("you. It"); + + String message = "Your dodgy necklace protects you. It has 1 charge left."; + MessageNode messageNode = mock(MessageNode.class); + when(messageNode.getValue()).thenReturn(message); + + ChatMessage chatMessage = new ChatMessage(); + chatMessage.setType(ChatMessageType.PUBLICCHAT); + chatMessage.setMessageNode(messageNode); + + chatNotificationsPlugin.startUp(); // load highlight config + chatNotificationsPlugin.onChatMessage(chatMessage); + + verify(messageNode).setValue("Your dodgy necklace protects you. It has 1 charge left."); + } + + @Test + public void testPreceedingColor() + { + when(config.highlightWordsString()).thenReturn("you. It"); + + String message = "Your dodgy necklace protects you. It has 1 charge left."; + MessageNode messageNode = mock(MessageNode.class); + when(messageNode.getValue()).thenReturn(message); + + ChatMessage chatMessage = new ChatMessage(); + chatMessage.setType(ChatMessageType.PUBLICCHAT); + chatMessage.setMessageNode(messageNode); + + chatNotificationsPlugin.startUp(); // load highlight config + chatNotificationsPlugin.onChatMessage(chatMessage); + + verify(messageNode).setValue("Your dodgy necklace protects you. It has 1 charge left."); + } + + @Test + public void testEmoji() + { + when(config.highlightWordsString()).thenReturn("test"); + + String message = "emoji test "; + MessageNode messageNode = mock(MessageNode.class); + when(messageNode.getValue()).thenReturn(message); + + ChatMessage chatMessage = new ChatMessage(); + chatMessage.setType(ChatMessageType.PUBLICCHAT); + chatMessage.setMessageNode(messageNode); + + chatNotificationsPlugin.startUp(); // load highlight config + chatNotificationsPlugin.onChatMessage(chatMessage); + + verify(messageNode).setValue("emoji test "); + } + + @Test + public void testNonMatchedColors() + { + when(config.highlightWordsString()).thenReturn("test"); + + String message = "color test "; + MessageNode messageNode = mock(MessageNode.class); + when(messageNode.getValue()).thenReturn(message); + + ChatMessage chatMessage = new ChatMessage(); + chatMessage.setType(ChatMessageType.PUBLICCHAT); + chatMessage.setMessageNode(messageNode); + + chatNotificationsPlugin.startUp(); // load highlight config + chatNotificationsPlugin.onChatMessage(chatMessage); + + verify(messageNode).setValue("color test "); + } + @Test public void highlightListTest() { @@ -144,4 +220,10 @@ public class ChatNotificationsPluginTest assertEquals("a", iterator.next()); assertEquals("test", iterator.next()); } + + @Test + public void testStripColor() + { + assertEquals("you. It", ChatNotificationsPlugin.stripColor("you. It")); + } } \ No newline at end of file From c94dd00a05d3d708379fa10c5eb0989632e12a36 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 5 Sep 2019 19:50:10 -0400 Subject: [PATCH 4/5] clue plugin: support Prifddinas clues This adds hotcold solver support in Prifddinas, and allows coordinate clues to be located in the city. Modify coordinate clues to support "real" and "overworld" locations so that regardless of which region you are in, the overlays work for either. Closes #9459 --- .../plugins/cluescrolls/ClueScrollPlugin.java | 45 +++++++++++-- .../cluescrolls/clues/CoordinateClue.java | 35 ++++++++-- .../cluescrolls/clues/HotColdClue.java | 3 +- .../cluescrolls/clues/LocationClueScroll.java | 6 ++ .../cluescrolls/ClueScrollPluginTest.java | 64 +++++++++++++++++++ .../cluescrolls/clues/CoordinateClueTest.java | 2 +- 6 files changed, 142 insertions(+), 13 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.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 173a2b5aae..cd3dbed6c6 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 @@ -114,6 +114,13 @@ public class ClueScrollPlugin extends Plugin private static final Color HIGHLIGHT_BORDER_COLOR = Color.ORANGE; private static final Color HIGHLIGHT_HOVER_BORDER_COLOR = HIGHLIGHT_BORDER_COLOR.darker(); private static final Color HIGHLIGHT_FILL_COLOR = new Color(0, 255, 0, 20); + private static final int[] REGION_MIRRORS = { + // Prifddinas + 12894, 8755, + 12895, 8756, + 13150, 9011, + 13151, 9012 + }; @Getter private ClueScroll clue; @@ -374,12 +381,13 @@ public class ClueScrollPlugin extends Plugin if (clue instanceof LocationClueScroll) { - final WorldPoint location = ((LocationClueScroll) clue).getLocation(); + final WorldPoint[] locations = ((LocationClueScroll) clue).getLocations(); - if (location != null) + for (WorldPoint location : locations) { // Only set the location hint arrow if we do not already have more accurate location - if (config.displayHintArrows() + if (location.isInScene(client) + && config.displayHintArrows() && (client.getHintArrowNpc() == null || !npcsToMark.contains(client.getHintArrowNpc()))) { @@ -610,7 +618,11 @@ public class ClueScrollPlugin extends Plugin minX *= -1; } - return new CoordinateClue(text, coordinatesToWorldPoint(degX, minX, degY, minY)); + WorldPoint coordinate = coordinatesToWorldPoint(degX, minX, degY, minY); + // Convert from overworld to real + WorldPoint mirrorPoint = getMirrorPoint(coordinate, false); + // Use mirror point as mirrorLocation if there is one + return new CoordinateClue(text, coordinate, coordinate == mirrorPoint ? null : mirrorPoint); } /** @@ -812,4 +824,29 @@ public class ClueScrollPlugin extends Plugin newScroll ); } + + /** + * Translate a coordinate either between overworld and real, or real and overworld + * + * @param worldPoint + * @param toOverworld whether to convert to overworld coordinates, or to real coordinates + * @return + */ + public static WorldPoint getMirrorPoint(WorldPoint worldPoint, boolean toOverworld) + { + int region = worldPoint.getRegionID(); + for (int i = 0; i < REGION_MIRRORS.length; i += 2) + { + int real = REGION_MIRRORS[i]; + int overworld = REGION_MIRRORS[i + 1]; + + // Test against what we are converting from + if (region == (toOverworld ? real : overworld)) + { + return WorldPoint.fromRegion(toOverworld ? overworld : real, + worldPoint.getRegionX(), worldPoint.getRegionY(), worldPoint.getPlane()); + } + } + return worldPoint; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java index 2fb7891866..268e03f5a0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.cluescrolls.clues; import com.google.common.collect.ImmutableMap; import java.awt.Color; import java.awt.Graphics2D; +import javax.annotation.Nullable; import lombok.Getter; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; @@ -198,14 +199,33 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati private final String text; private final WorldPoint location; + /** + * For regions which are mirrored, the location of the the clue in the mirrored region. + */ + @Nullable + private final WorldPoint mirrorLocation; - public CoordinateClue(String text, WorldPoint location) + public CoordinateClue(String text, WorldPoint location, WorldPoint mirrorLocation) { this.text = text; this.location = location; + this.mirrorLocation = mirrorLocation; setRequiresSpade(true); } + @Override + public WorldPoint[] getLocations() + { + if (mirrorLocation != null) + { + return new WorldPoint[]{location, mirrorLocation}; + } + else + { + return new WorldPoint[]{location}; + } + } + @Override public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) { @@ -229,13 +249,14 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati @Override public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) { - LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); - - if (localLocation == null) + for (WorldPoint worldPoint : getLocations()) { - return; - } + LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), worldPoint); - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); + if (localLocation != null) + { + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); + } + } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java index a4f4126656..2499379be4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java @@ -292,7 +292,8 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat return false; } - final WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); + // Convert from real to overworld + final WorldPoint localWorld = ClueScrollPlugin.getMirrorPoint(plugin.getClient().getLocalPlayer().getWorldLocation(), true); if (localWorld == null) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/LocationClueScroll.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/LocationClueScroll.java index 323e0a498e..194aefcb5a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/LocationClueScroll.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/LocationClueScroll.java @@ -29,4 +29,10 @@ import net.runelite.api.coords.WorldPoint; public interface LocationClueScroll { WorldPoint getLocation(); + + default WorldPoint[] getLocations() + { + WorldPoint location = getLocation(); + return location == null ? new WorldPoint[0] : new WorldPoint[]{location}; + } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java new file mode 100644 index 0000000000..d1585382d4 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Hydrox6 + * Copyright (c) 2019 Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.cluescrolls; + +import net.runelite.api.coords.WorldPoint; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import org.junit.Test; + +public class ClueScrollPluginTest +{ + @Test + public void getGetMirrorPoint() + { + WorldPoint point, converted; + + // Zalcano's entrance portal + point = new WorldPoint(3282, 6058, 0); + converted = ClueScrollPlugin.getMirrorPoint(point, true); + assertNotEquals(point, converted); + + // Elven Crystal Chest, which is upstairs + point = new WorldPoint(3273, 6082, 2); + converted = ClueScrollPlugin.getMirrorPoint(point, true); + assertNotEquals(point, converted); + + // Around the area of the Elite coordinate clue + point = new WorldPoint(2185, 3280, 0); + // To overworld + converted = ClueScrollPlugin.getMirrorPoint(point, true); + assertEquals(point, converted); + // To real + converted = ClueScrollPlugin.getMirrorPoint(point, false); + assertNotEquals(point, converted); + + // Brugsen Bursen, Grand Exchange + point = new WorldPoint(3165, 3477, 0); + converted = ClueScrollPlugin.getMirrorPoint(point, false); + assertEquals(point, converted); + } +} \ No newline at end of file diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClueTest.java index 6896928b29..d3854d843f 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClueTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClueTest.java @@ -33,6 +33,6 @@ public class CoordinateClueTest public void testDuplicateCoordinates() { // If this doesn't throw then the clues map doesn't have duplicate keys - new CoordinateClue("test", new WorldPoint(0, 0, 0)); + new CoordinateClue("test", new WorldPoint(0, 0, 0), null); } } \ No newline at end of file From d066ca97a3f1b237872c3cc6c2aea5890a1acab7 Mon Sep 17 00:00:00 2001 From: Hunter Harloff Date: Sun, 8 Sep 2019 10:56:59 -0400 Subject: [PATCH 5/5] hooks: draw ABOVE_MAP before ABOVE_WIDGETS --- .../src/main/java/net/runelite/client/callback/Hooks.java | 2 +- .../net/runelite/client/plugins/devtools/DevToolsOverlay.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java index 96f4a90bbe..4365d045f6 100644 --- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java +++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java @@ -450,8 +450,8 @@ public class Hooks implements Callbacks try { - renderer.render(graphics2d, OverlayLayer.ABOVE_WIDGETS); renderer.render(graphics2d, OverlayLayer.ABOVE_MAP); + renderer.render(graphics2d, OverlayLayer.ABOVE_WIDGETS); } catch (Exception ex) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java index 8bf45eaf83..9bb7292dc3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java @@ -64,6 +64,7 @@ import net.runelite.client.ui.FontManager; 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; import net.runelite.client.ui.overlay.tooltip.Tooltip; import net.runelite.client.ui.overlay.tooltip.TooltipManager; @@ -102,7 +103,8 @@ class DevToolsOverlay extends Overlay private DevToolsOverlay(Client client, DevToolsPlugin plugin, TooltipManager toolTipManager) { setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_MAP); + setLayer(OverlayLayer.ABOVE_WIDGETS); + setPriority(OverlayPriority.HIGHEST); this.client = client; this.plugin = plugin; this.toolTipManager = toolTipManager;