From 95556aadc75a602ca9166fd9bc86252895512a94 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Wed, 18 Mar 2020 17:53:34 -0700 Subject: [PATCH 01/11] widget: Expose widget model getters and setters This commit also adds these widget properties to the widget inspector dev tool. --- .../java/net/runelite/api/widgets/Widget.java | 84 ++++++++++++++++++- .../runelite/api/widgets/WidgetModelType.java | 35 ++++++++ .../devtools/WidgetInfoTableModel.java | 7 +- 3 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 runelite-api/src/main/java/net/runelite/api/widgets/WidgetModelType.java diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java index f44e61e448..5a827a8ed6 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java @@ -243,11 +243,91 @@ public interface Widget /** * Gets the model ID displayed in the widget. - * - * @return the model ID */ int getModelId(); + /** + * Sets the model ID displayed in the widget. + * + * @param modelId the new model ID + */ + void setModelId(int modelId); + + /** + * Gets the model type of the widget. + * + * @see WidgetModelType + */ + int getModelType(); + + /** + * Sets the model type of the widget. + * + * @param type the new model type + * @see WidgetModelType + */ + void setModelType(int type); + + /** + * Gets the x rotation of the model displayed in the widget. + * 0 = no rotation, 2047 = full rotation + */ + int getRotationX(); + + /** + * Sets the x rotation of the model displayed in the widget. + *
+ * Note: Setting this value outside of the input range defined by {@link Widget#getRotationX()} will cause a client + * crash. + * + * @param modelX the new model x rotation value + */ + void setRotationX(int modelX); + + /** + * Gets the y rotation of the model displayed in the widget. + * 0 = no rotation, 2047 = full rotation + */ + int getRotationY(); + + /** + * Sets the y rotation of the model displayed in the widget. + *
+ * Note: Setting this value outside of the input range defined by {@link Widget#getRotationY()} will cause a client + * crash. + * + * @param modelY the new model y rotation value + */ + void setRotationY(int modelY); + + /** + * Gets the z rotation of the model displayed in the widget. + * 0 = no rotation, 2047 = full rotation + */ + int getRotationZ(); + + /** + * Sets the z rotation of the model displayed in the widget. + *
+ * Note: Setting this value outside of the input range defined by {@link Widget#getRotationZ()} will cause a client + * crash. + * + * @param modelZ the new model z rotation value + */ + void setRotationZ(int modelZ); + + /** + * Gets the amount zoomed in on the model displayed in the widget. + */ + int getModelZoom(); + + /** + * Sets the amount zoomed in on the model displayed in the widget. + * + * @param modelZoom the new model zoom value + */ + void setModelZoom(int modelZoom); + /** * Gets the sprite ID displayed in the widget. * diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetModelType.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetModelType.java new file mode 100644 index 0000000000..ff68eef617 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetModelType.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020, Jordan + * 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.api.widgets; + +public class WidgetModelType +{ + public static final int NULL = 0; + public static final int MODEL = 1; + public static final int NPC_CHATHEAD = 2; + public static final int LOCAL_PLAYER_CHATHEAD = 3; + public static final int ITEM = 4; + public static final int PLAYER = 5; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java index acd8851c0b..6623838871 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java @@ -155,7 +155,12 @@ public class WidgetInfoTableModel extends AbstractTableModel out.add(new WidgetField<>("ItemId", Widget::getItemId, Widget::setItemId, Integer.class)); out.add(new WidgetField<>("ItemQuantity", Widget::getItemQuantity, Widget::setItemQuantity, Integer.class)); out.add(new WidgetField<>("ItemQuantityMode", Widget::getItemQuantityMode, Widget::setItemQuantityMode, Integer.class)); - out.add(new WidgetField<>("ModelId", Widget::getModelId)); + out.add(new WidgetField<>("ModelId", Widget::getModelId, Widget::setModelId, Integer.class)); + out.add(new WidgetField<>("ModelType", Widget::getModelType, Widget::setModelType, Integer.class)); + out.add(new WidgetField<>("RotationX", Widget::getRotationX, Widget::setRotationX, Integer.class)); + out.add(new WidgetField<>("RotationY", Widget::getRotationY, Widget::setRotationY, Integer.class)); + out.add(new WidgetField<>("RotationZ", Widget::getRotationZ, Widget::setRotationZ, Integer.class)); + out.add(new WidgetField<>("ModelZoom", Widget::getModelZoom, Widget::setModelZoom, Integer.class)); out.add(new WidgetField<>("SpriteId", Widget::getSpriteId, Widget::setSpriteId, Integer.class)); out.add(new WidgetField<>("BorderType", Widget::getBorderType, Widget::setBorderType, Integer.class)); out.add(new WidgetField<>("IsIf3", Widget::isIf3)); From c930a5d261686c5e0dfd8c445fdfbe03c85bf2ec Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 24 Mar 2020 11:24:31 -0400 Subject: [PATCH 02/11] http-api: add world region to World Add a WorldRegion to convert from location id to region Co-authored-by: melkypie --- .../net/runelite/http/api/worlds/World.java | 5 ++ .../runelite/http/api/worlds/WorldRegion.java | 74 +++++++++++++++++++ .../service/worlds/WorldsServiceTest.java | 5 ++ .../plugins/worldhopper/WorldTableRow.java | 30 +++++--- 4 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/World.java b/http-api/src/main/java/net/runelite/http/api/worlds/World.java index 2c1e6f6798..70bc2c8237 100644 --- a/http-api/src/main/java/net/runelite/http/api/worlds/World.java +++ b/http-api/src/main/java/net/runelite/http/api/worlds/World.java @@ -38,4 +38,9 @@ public class World private String activity; private int location; private int players; + + public WorldRegion getRegion() + { + return WorldRegion.valueOf(location); + } } diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java b/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java new file mode 100644 index 0000000000..2c391e91f4 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/worlds/WorldRegion.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020, melky + * 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.http.api.worlds; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Holds the data for each world's region (location) + */ +@AllArgsConstructor +@Getter +public enum WorldRegion +{ + UNITED_STATES_OF_AMERICA("US", "USA"), + UNITED_KINGDOM("GB", "GBR"), + AUSTRALIA("AU", "AUS"), + GERMANY("DE", "DEU"); + + /** + * ISO-3166-1 alpha-2 country code + */ + private final String alpha2; + /** + * ISO-3166-1 alpha-3 country code + */ + private final String alpha3; + + /** + * Gets the region using the location id + * {@link WorldRegion} value. + * + * @param locationId the location id of world + * @return WorldRegion the region of the world + */ + public static WorldRegion valueOf(int locationId) + { + switch (locationId) + { + case 0: + return UNITED_STATES_OF_AMERICA; + case 1: + return UNITED_KINGDOM; + case 3: + return AUSTRALIA; + case 7: + return GERMANY; + default: + return null; + } + } +} diff --git a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java b/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java index 152a6e4e5a..a083bba0df 100644 --- a/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java +++ b/http-service/src/test/java/net/runelite/http/service/worlds/WorldsServiceTest.java @@ -77,6 +77,11 @@ public class WorldsServiceTest World world = worldResult.findWorld(385); assertNotNull(world); assertTrue(world.getTypes().contains(WorldType.SKILL_TOTAL)); + + for (World testWorld : worldResult.getWorlds()) + { + assertNotNull("Missing a region in WorldRegion enum", testWorld.getRegion()); + } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java index 2aea475eb0..d3f6315ba2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java @@ -43,6 +43,7 @@ import lombok.Getter; import net.runelite.client.ui.FontManager; import net.runelite.client.util.ImageUtil; import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldRegion; import net.runelite.http.api.worlds.WorldType; class WorldTableRow extends JPanel @@ -57,7 +58,6 @@ class WorldTableRow extends JPanel private static final int PING_COLUMN_WIDTH = 35; private static final Color CURRENT_WORLD = new Color(66, 227, 17); - private static final Color UNAVAILABLE_WORLD = Color.GRAY.darker().darker(); private static final Color DANGEROUS_WORLD = new Color(251, 62, 62); private static final Color TOURNAMENT_WORLD = new Color(79, 145, 255); private static final Color MEMBERS_WORLD = new Color(210, 193, 53); @@ -326,26 +326,36 @@ class WorldTableRow extends JPanel worldField = new JLabel(world.getId() + ""); - JLabel flag = new JLabel(getFlag(world.getLocation())); - - column.add(flag, BorderLayout.WEST); + ImageIcon flagIcon = getFlag(world.getRegion()); + if (flagIcon != null) + { + JLabel flag = new JLabel(flagIcon); + column.add(flag, BorderLayout.WEST); + } column.add(worldField, BorderLayout.CENTER); return column; } - private ImageIcon getFlag(int locationId) + private static ImageIcon getFlag(WorldRegion region) { - switch (locationId) + if (region == null) { - case 0: + return null; + } + + switch (region) + { + case UNITED_STATES_OF_AMERICA: return FLAG_US; - case 1: + case UNITED_KINGDOM: return FLAG_UK; - case 3: + case AUSTRALIA: return FLAG_AUS; - default: + case GERMANY: return FLAG_GER; + default: + return null; } } } From 21b7ccd2e8cf821048f49a93f81aff89fc22558a Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 24 Mar 2020 11:24:35 -0400 Subject: [PATCH 03/11] raids: add world region to scout overlay Adds the region of the world the scout was performed. Before: W303 Username Now: W303 (DE) Username Co-authored-by: melkypie --- .../client/plugins/raids/RaidsOverlay.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java index 3ff46b528d..f4441a8151 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java @@ -35,6 +35,7 @@ import net.runelite.api.ClanMemberManager; import net.runelite.api.Client; import static net.runelite.api.MenuAction.RUNELITE_OVERLAY; import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; +import net.runelite.client.game.WorldService; import net.runelite.client.plugins.raids.solver.Room; import net.runelite.client.ui.overlay.Overlay; import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; @@ -45,6 +46,9 @@ import net.runelite.client.ui.overlay.components.ComponentConstants; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; +import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldRegion; +import net.runelite.http.api.worlds.WorldResult; public class RaidsOverlay extends Overlay { @@ -61,6 +65,9 @@ public class RaidsOverlay extends Overlay @Setter private boolean scoutOverlayShown = false; + @Inject + private WorldService worldService; + @Inject private RaidsOverlay(Client client, RaidsPlugin plugin, RaidsConfig config) { @@ -113,7 +120,20 @@ public class RaidsOverlay extends Overlay color = Color.RED; ClanMemberManager clanMemberManager = client.getClanMemberManager(); FontMetrics metrics = graphics.getFontMetrics(); + String worldString = "W" + client.getWorld(); + WorldResult worldResult = worldService.getWorlds(); + if (worldResult != null) + { + World world = worldResult.findWorld(client.getWorld()); + WorldRegion region = world.getRegion(); + if (region != null) + { + String countryCode = region.getAlpha2(); + worldString += " (" + countryCode + ")"; + } + } + String clanOwner = "Join a CC"; if (clanMemberManager != null) { From 91ae43dd2d9c89d9ae897e7f1c29d6c98625fa97 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 24 Mar 2020 13:55:29 -0400 Subject: [PATCH 04/11] api: make IterableHashTable generic --- runelite-api/src/main/java/net/runelite/api/Client.java | 2 +- .../src/main/java/net/runelite/api/IterableHashTable.java | 4 ++-- .../runelite/client/plugins/chatfilter/ChatFilterPlugin.java | 2 +- .../runelite/client/plugins/timestamp/TimestampPlugin.java | 2 +- .../client/plugins/chatfilter/ChatFilterPluginTest.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 31feace4cf..e43a067701 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -861,7 +861,7 @@ public interface Client extends GameEngine * * @return the map */ - IterableHashTable getMessages(); + IterableHashTable getMessages(); /** * Gets the viewport widget. diff --git a/runelite-api/src/main/java/net/runelite/api/IterableHashTable.java b/runelite-api/src/main/java/net/runelite/api/IterableHashTable.java index bc8c23ccd9..48894f1863 100644 --- a/runelite-api/src/main/java/net/runelite/api/IterableHashTable.java +++ b/runelite-api/src/main/java/net/runelite/api/IterableHashTable.java @@ -24,7 +24,7 @@ */ package net.runelite.api; -public interface IterableHashTable extends Iterable +public interface IterableHashTable extends Iterable { - Node get(long hash); + T get(long hash); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java index d78f2c8bcd..67561b0833 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java @@ -135,7 +135,7 @@ public class ChatFilterPlugin extends Plugin return; } - MessageNode messageNode = (MessageNode) client.getMessages().get(messageId); + MessageNode messageNode = client.getMessages().get(messageId); String name = messageNode.getName(); if (!shouldFilterPlayerMessage(name)) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timestamp/TimestampPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/timestamp/TimestampPlugin.java index b2fb6d3e61..f49a4be15f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timestamp/TimestampPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timestamp/TimestampPlugin.java @@ -105,7 +105,7 @@ public class TimestampPlugin extends Plugin int messageId = intStack[intStackSize - 1]; - MessageNode messageNode = (MessageNode) client.getMessages().get(messageId); + MessageNode messageNode = client.getMessages().get(messageId); String timestamp = generateTimestamp(messageNode.getTimestamp(), ZoneId.systemDefault()) + " "; diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java index 07a45e7a29..dfa8a08712 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java @@ -90,7 +90,7 @@ public class ChatFilterPluginTest int[] simulatedIntStack = new int[]{1, messageType.getType(), 1}; // is msg allowed to show, ChatMessageType.PUBLICCHAT, message id String[] simulatedStringStack = new String[]{chatMessage}; - IterableHashTable messageTable = mock(IterableHashTable.class); + IterableHashTable messageTable = mock(IterableHashTable.class); MessageNode mockedMsgNode = mockMessageNode(sender); when(client.getIntStack()).thenReturn(simulatedIntStack); when(client.getIntStackSize()).thenReturn(simulatedIntStack.length); From 71e4b5d9ad43ccf968380f5cf6845a0d20849865 Mon Sep 17 00:00:00 2001 From: dekvall Date: Thu, 26 Dec 2019 05:34:04 +0100 Subject: [PATCH 05/11] herbiboar: use guaranteed tracks when highlighting path There's a set of guaranteed tracks that can be used when calculating the path when tracking herbiboars. The tracks are listed on the osrs wiki. Co-authored-by: Jordan Atwood --- .../main/java/net/runelite/api/Varbits.java | 9 +- .../herbiboars/HerbiboarMinimapOverlay.java | 43 +-- .../plugins/herbiboars/HerbiboarOverlay.java | 99 +++---- .../plugins/herbiboars/HerbiboarPlugin.java | 271 +++++++++++------- .../plugins/herbiboars/HerbiboarRule.java | 110 +++++++ .../herbiboars/HerbiboarSearchSpot.java | 180 ++++++++++++ .../plugins/herbiboars/HerbiboarStart.java | 55 ++++ .../plugins/herbiboars/HerbiboarTrail.java | 109 ------- .../plugins/herbiboars/TrailToSpot.java | 60 ++++ 9 files changed, 641 insertions(+), 295 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarRule.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarSearchSpot.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarStart.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarTrail.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/TrailToSpot.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 bea1e9b830..b9b8a7a4ed 100644 --- a/runelite-api/src/main/java/net/runelite/api/Varbits.java +++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java @@ -219,7 +219,14 @@ public enum Varbits HB_TRAIL_31372(5750), HB_FINISH(5766), - HB_STARTED(5767), //not working + + /** + * Started hunting Herbiboar. + *
+ * NOTE: This value remains at 0 even after starting a Herbiboar trail up until searching the first object along the + * hunting path. + */ + HB_STARTED(5767), /** * Barbarian Assault diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarMinimapOverlay.java index fff22cbc39..acbdbdfb89 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarMinimapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarMinimapOverlay.java @@ -35,7 +35,7 @@ import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayUtil; -public class HerbiboarMinimapOverlay extends Overlay +class HerbiboarMinimapOverlay extends Overlay { private final HerbiboarPlugin plugin; private final HerbiboarConfig config; @@ -52,29 +52,30 @@ public class HerbiboarMinimapOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - if (config.isTrailShown() && plugin.isInHerbiboarArea()) + if (!config.isTrailShown() || !plugin.isInHerbiboarArea()) { - HerbiboarTrail currentTrail = plugin.getCurrentTrail(); - int finishId = plugin.getFinishId(); - Set shownTrailIds = plugin.getShownTrails(); - - for (TileObject tileObject : plugin.getTrails().values()) - { - int id = tileObject.getId(); - Point minimapLocation = tileObject.getMinimapLocation(); - - if (minimapLocation == null) - { - continue; - } - - if (shownTrailIds.contains(id) && (finishId > 0 || (currentTrail != null && currentTrail.getTrailId() != id && currentTrail.getTrailId() + 1 != id))) - { - OverlayUtil.renderMinimapLocation(graphics, minimapLocation, config.getTrailColor()); - } - } + return null; } + TrailToSpot nextTrail = plugin.getNextTrail(); + int finishId = plugin.getFinishId(); + Set shownTrailIds = plugin.getShownTrails(); + + for (TileObject tileObject : plugin.getTrails().values()) + { + int id = tileObject.getId(); + Point minimapLocation = tileObject.getMinimapLocation(); + + if (minimapLocation == null) + { + continue; + } + + if (shownTrailIds.contains(id) && (finishId > 0 || nextTrail != null && !nextTrail.getFootprintIds().contains(id))) + { + OverlayUtil.renderMinimapLocation(graphics, minimapLocation, config.getTrailColor()); + } + } return null; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarOverlay.java index a97f5d9d49..5389cd6fd0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarOverlay.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.herbiboars; +import com.google.common.collect.Iterables; import com.google.inject.Inject; import java.awt.Color; import java.awt.Dimension; @@ -59,17 +60,14 @@ class HerbiboarOverlay extends Overlay return null; } - HerbiboarTrail currentTrail = plugin.getCurrentTrail(); - + HerbiboarSearchSpot.Group currentGroup = plugin.getCurrentGroup(); + TrailToSpot nextTrail = plugin.getNextTrail(); int finishId = plugin.getFinishId(); // Draw start objects - if (config.isStartShown() && (currentTrail == null && finishId == 0)) + if (config.isStartShown() && (currentGroup == null && finishId == 0)) { - plugin.getStarts().values().forEach((obj) -> - { - OverlayUtil.renderTileOverlay(graphics, obj, "", config.getStartColor()); - }); + plugin.getStarts().values().forEach((obj) -> OverlayUtil.renderTileOverlay(graphics, obj, "", config.getStartColor())); } // Draw trails @@ -79,7 +77,7 @@ class HerbiboarOverlay extends Overlay plugin.getTrails().values().forEach((x) -> { int id = x.getId(); - if (shownTrailIds.contains(id) && (finishId > 0 || (currentTrail != null && currentTrail.getTrailId() != id && currentTrail.getTrailId() + 1 != id))) + if (shownTrailIds.contains(id) && (finishId > 0 || nextTrail != null && !nextTrail.getFootprintIds().contains(id))) { OverlayUtil.renderTileOverlay(graphics, x, "", config.getTrailColor()); } @@ -87,35 +85,20 @@ class HerbiboarOverlay extends Overlay } // Draw trail objects (mushrooms, mud, etc) - if (config.isObjectShown() && currentTrail != null) + if (config.isObjectShown() && !(finishId > 0 || currentGroup == null)) { - int currentPath = plugin.getCurrentPath(); - WorldPoint[] trailLocs = currentTrail.getObjectLocs(currentPath); - for (WorldPoint trailLoc : trailLocs) + if (plugin.isRuleApplicable()) { - if (trailLoc == null) + WorldPoint correct = Iterables.getLast(plugin.getCurrentPath()).getLocation(); + TileObject object = plugin.getTrailObjects().get(correct); + drawObjectLocation(graphics, object, config.getObjectColor()); + } + else + { + for (WorldPoint trailLoc : HerbiboarSearchSpot.getGroupLocations(plugin.getCurrentGroup())) { - continue; - } - - TileObject object = plugin.getTrailObjects().get(trailLoc); - if (object != null) - { - if (config.showClickBoxes()) - { - Shape clickbox = object.getClickbox(); - if (clickbox != null) - { - graphics.setColor(config.getObjectColor()); - graphics.draw(clickbox); - graphics.setColor(new Color(255, 0, 255, 20)); - graphics.fill(clickbox); - } - } - else - { - OverlayUtil.renderTileOverlay(graphics, object, "", config.getObjectColor()); - } + TileObject object = plugin.getTrailObjects().get(trailLoc); + drawObjectLocation(graphics, object, config.getObjectColor()); } } } @@ -125,27 +108,35 @@ class HerbiboarOverlay extends Overlay { WorldPoint finishLoc = plugin.getEndLocations().get(finishId - 1); TileObject object = plugin.getTunnels().get(finishLoc); - if (object != null) - { - if (config.showClickBoxes()) - { - Shape clickbox = object.getClickbox(); - if (clickbox != null) - { - Color col = config.getObjectColor(); - graphics.setColor(col); - graphics.draw(clickbox); - graphics.setColor(new Color(col.getRed(), col.getGreen(), col.getBlue(), 20)); - graphics.fill(clickbox); - } - } - else - { - OverlayUtil.renderTileOverlay(graphics, object, "", config.getTunnelColor()); - } - } + drawObjectLocation(graphics, object, config.getTunnelColor()); } return null; } -} \ No newline at end of file + + private void drawObjectLocation(Graphics2D graphics, TileObject object, Color color) + { + if (object == null) + { + return; + } + + if (config.showClickBoxes()) + { + Shape clickbox = object.getClickbox(); + if (clickbox != null) + { + Color clickBoxColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), 20); + + graphics.setColor(color); + graphics.draw(clickbox); + graphics.setColor(clickBoxColor); + graphics.fill(clickbox); + } + } + else + { + OverlayUtil.renderTileOverlay(graphics, object, "", color); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarPlugin.java index 83e59c19a4..02288075c5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarPlugin.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Tyler + * Copyright (c) 2020, dekvall * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,8 +25,10 @@ */ package net.runelite.client.plugins.herbiboars; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; import com.google.inject.Provides; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -33,14 +36,15 @@ import java.util.Map; import java.util.Set; import javax.inject.Inject; import lombok.Getter; -import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.MenuAction; import static net.runelite.api.ObjectID.DRIFTWOOD_30523; import static net.runelite.api.ObjectID.MUSHROOM_30520; import static net.runelite.api.ObjectID.ROCK_30519; import static net.runelite.api.ObjectID.ROCK_30521; import static net.runelite.api.ObjectID.ROCK_30522; -import net.runelite.api.Tile; import net.runelite.api.TileObject; import net.runelite.api.Varbits; import net.runelite.api.coords.WorldPoint; @@ -51,21 +55,27 @@ import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GroundObjectChanged; import net.runelite.api.events.GroundObjectDespawned; import net.runelite.api.events.GroundObjectSpawned; +import net.runelite.api.events.MenuOptionClicked; 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; +import net.runelite.client.util.Text; +import org.apache.commons.lang3.ArrayUtils; @PluginDescriptor( name = "Herbiboar", description = "Highlight starting rocks, trails, and the objects to search at the end of each trail", tags = {"herblore", "hunter", "skilling", "overlay"} ) +@Slf4j +@Getter public class HerbiboarPlugin extends Plugin { - private static final List END_LOCATIONS = Arrays.asList( + private static final List END_LOCATIONS = ImmutableList.of( new WorldPoint(3693, 3798, 0), new WorldPoint(3702, 3808, 0), new WorldPoint(3703, 3826, 0), @@ -77,7 +87,7 @@ public class HerbiboarPlugin extends Plugin new WorldPoint(3681, 3863, 0) ); - private static final List START_OBJECT_IDS = Arrays.asList( + private static final Set START_OBJECT_IDS = ImmutableSet.of( ROCK_30519, MUSHROOM_30520, ROCK_30521, @@ -85,16 +95,19 @@ public class HerbiboarPlugin extends Plugin DRIFTWOOD_30523 ); - private static final int[] HERBIBOAR_REGIONS = { + private static final List HERBIBOAR_REGIONS = ImmutableList.of( 14652, 14651, 14908, 14907 - }; + ); @Inject private Client client; + @Inject + private ClientThread clientThread; + @Inject private OverlayManager overlayManager; @@ -104,39 +117,43 @@ public class HerbiboarPlugin extends Plugin @Inject private HerbiboarMinimapOverlay minimapOverlay; - @Getter + /** + * Objects which appear at the beginning of Herbiboar hunting trails + */ + private final Map starts = new HashMap<>(); + /** + * Herbiboar hunting "footstep" trail objects + */ + private final Map trails = new HashMap<>(); + /** + * Objects which trigger next trail (mushrooms, mud, seaweed, etc) + */ + private final Map trailObjects = new HashMap<>(); + /** + * Tunnel where the Herbiboar is hiding at the end of a trail + */ + private final Map tunnels = new HashMap<>(); + /** + * Trail object IDs which should be highlighted + */ + private final Set shownTrails = new HashSet<>(); + /** + * Sequence of herbiboar spots searched along the current trail + */ + private final List currentPath = Lists.newArrayList(); + private boolean inHerbiboarArea; - - @Getter - private Map trails = new HashMap<>(); - - @Getter - private Map tunnels = new HashMap<>(); - - @Getter - private Map starts = new HashMap<>(); - - @Getter - private Map trailObjects = new HashMap<>(); - - @Getter - @Setter - private Set shownTrails = new HashSet<>(); - - @Getter - @Setter - private HerbiboarTrail currentTrail; - - @Getter - @Setter - private int currentPath; - - @Getter - @Setter + private TrailToSpot nextTrail; + private HerbiboarSearchSpot.Group currentGroup; private int finishId; + private boolean started; + private WorldPoint startPoint; + private HerbiboarStart startSpot; + private boolean ruleApplicable; + @Provides - HerbiboarConfig getConfig(ConfigManager configManager) + HerbiboarConfig provideConfig(ConfigManager configManager) { return configManager.getConfig(HerbiboarConfig.class); } @@ -146,7 +163,15 @@ public class HerbiboarPlugin extends Plugin { overlayManager.add(overlay); overlayManager.add(minimapOverlay); - inHerbiboarArea = checkArea(); + + if (client.getGameState() == GameState.LOGGED_IN) + { + clientThread.invokeLater(() -> + { + inHerbiboarArea = checkArea(); + updateTrailData(); + }); + } } @Override @@ -154,61 +179,105 @@ public class HerbiboarPlugin extends Plugin { overlayManager.remove(overlay); overlayManager.remove(minimapOverlay); + resetTrailData(); + clearCache(); + inHerbiboarArea = false; } private void updateTrailData() { - currentTrail = null; - currentPath = -1; + if (!isInHerbiboarArea()) + { + return; + } + + boolean pathActive = false; + boolean wasStarted = started; // Get trail data - for (HerbiboarTrail trail : HerbiboarTrail.values()) + for (HerbiboarSearchSpot spot : HerbiboarSearchSpot.values()) { - int trailId = trail.getTrailId(); - int value = client.getVar(trail.getVarbit()); + for (TrailToSpot trail : spot.getTrails()) + { + int value = client.getVar(trail.getVarbit()); - if (value > 0) - { - shownTrails.add(trailId); - shownTrails.add(trailId + 1); - } - if (value == 1 || value == 2) - { - currentTrail = trail; - currentPath = value; + if (value == trail.getValue()) + { + // The trail after you have searched the spot + currentGroup = spot.getGroup(); + nextTrail = trail; + + // You never visit the same spot twice + if (!currentPath.contains(spot)) + { + currentPath.add(spot); + } + } + else if (value > 0) + { + // The current trail + shownTrails.addAll(trail.getFootprintIds()); + pathActive = true; + } } } - // Get finish data finishId = client.getVar(Varbits.HB_FINISH); - if (finishId > 0 && currentTrail != null) + + // The started varbit doesn't get set until the first spot of the rotation has been searched + // so we need to use the current group as an indicator of the rotation being started + started = client.getVar(Varbits.HB_STARTED) > 0 || currentGroup != null; + boolean finished = !pathActive && started; + + if (!wasStarted && started) { - shownTrails.add(currentTrail.getTrailId()); - shownTrails.add(currentTrail.getTrailId() + 1); - currentTrail = null; - currentPath = -1; + startSpot = HerbiboarStart.from(startPoint); } - int started = client.getVar(Varbits.HB_STARTED); - if (currentPath == -1 && finishId == 0 && started == 0) + ruleApplicable = HerbiboarRule.canApplyRule(startSpot, currentPath); + + if (finished) { resetTrailData(); } } + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked menuOpt) + { + if (!inHerbiboarArea || started || MenuAction.GAME_OBJECT_FIRST_OPTION != menuOpt.getMenuAction()) + { + return; + } + + switch (Text.removeTags(menuOpt.getMenuTarget())) + { + case "Rock": + case "Mushroom": + case "Driftwood": + startPoint = WorldPoint.fromScene(client, menuOpt.getActionParam(), menuOpt.getWidgetId(), client.getPlane()); + } + } + private void resetTrailData() { - currentPath = 0; - currentTrail = null; - finishId = 0; + log.debug("Reset trail data"); shownTrails.clear(); + currentPath.clear(); + nextTrail = null; + currentGroup = null; + finishId = 0; + started = false; + startPoint = null; + startSpot = null; + ruleApplicable = false; } private void clearCache() { starts.clear(); - trailObjects.clear(); trails.clear(); + trailObjects.clear(); tunnels.clear(); } @@ -233,57 +302,55 @@ public class HerbiboarPlugin extends Plugin @Subscribe public void onVarbitChanged(VarbitChanged event) { - if (isInHerbiboarArea()) - { - updateTrailData(); - } + updateTrailData(); } @Subscribe public void onGameObjectSpawned(GameObjectSpawned event) { - onGameObject(event.getTile(), null, event.getGameObject()); + onTileObject(null, event.getGameObject()); } @Subscribe public void onGameObjectChanged(GameObjectChanged event) { - onGameObject(event.getTile(), event.getPrevious(), event.getGameObject()); + onTileObject(event.getPrevious(), event.getGameObject()); } @Subscribe public void onGameObjectDespawned(GameObjectDespawned event) { - onGameObject(event.getTile(), event.getGameObject(), null); + onTileObject(event.getGameObject(), null); } @Subscribe public void onGroundObjectSpawned(GroundObjectSpawned event) { - onGroundObject(event.getTile(), null, event.getGroundObject()); + onTileObject(null, event.getGroundObject()); } @Subscribe public void onGroundObjectChanged(GroundObjectChanged event) { - onGroundObject(event.getTile(), event.getPrevious(), event.getGroundObject()); + onTileObject(event.getPrevious(), event.getGroundObject()); } @Subscribe public void onGroundObjectDespawned(GroundObjectDespawned event) { - onGroundObject(event.getTile(), event.getGroundObject(), null); + onTileObject(event.getGroundObject(), null); } - // Store relevant GameObjects (starts, objects used to trigger next trails, and some tunnels) - private void onGameObject(Tile tile, TileObject oldObject, TileObject newObject) + // Store relevant GameObjects (starts, tracks on trails, objects used to trigger next trails, and tunnels) + private void onTileObject(TileObject oldObject, TileObject newObject) { if (oldObject != null) { WorldPoint oldLocation = oldObject.getWorldLocation(); + starts.remove(oldLocation); + trails.remove(oldLocation); trailObjects.remove(oldLocation); tunnels.remove(oldLocation); - starts.remove(oldLocation); } if (newObject == null) @@ -298,8 +365,15 @@ public class HerbiboarPlugin extends Plugin return; } + // Trails + if (HerbiboarSearchSpot.isTrail(newObject.getId())) + { + trails.put(newObject.getWorldLocation(), newObject); + return; + } + // GameObject to trigger next trail (mushrooms, mud, seaweed, etc) - if (HerbiboarTrail.getAllObjectLocs().contains(newObject.getWorldLocation())) + if (HerbiboarSearchSpot.isSearchSpot(newObject.getWorldLocation())) { trailObjects.put(newObject.getWorldLocation(), newObject); return; @@ -312,43 +386,20 @@ public class HerbiboarPlugin extends Plugin } } - // Store relevant GroundObjects (tracks on trails, and some tunnels) - private void onGroundObject(Tile tile, TileObject oldObject, TileObject newObject) - { - if (oldObject != null) - { - WorldPoint oldLocation = oldObject.getWorldLocation(); - trails.remove(oldLocation); - tunnels.remove(oldLocation); - } - - if (newObject == null) - { - return; - } - - //Trails - if (HerbiboarTrail.getTrailIds().contains(newObject.getId())) - { - trails.put(newObject.getWorldLocation(), newObject); - return; - } - - //Herbiboar tunnel - if (END_LOCATIONS.contains(newObject.getWorldLocation())) - { - tunnels.put(newObject.getWorldLocation(), newObject); - } - } - private boolean checkArea() { - return client.getMapRegions() != null && Arrays.stream(client.getMapRegions()) - .filter(x -> Arrays.stream(HERBIBOAR_REGIONS).anyMatch(y -> y == x)) - .toArray().length > 0; + final int[] mapRegions = client.getMapRegions(); + for (int region : HERBIBOAR_REGIONS) + { + if (ArrayUtils.contains(mapRegions, region)) + { + return true; + } + } + return false; } - public List getEndLocations() + List getEndLocations() { return END_LOCATIONS; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarRule.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarRule.java new file mode 100644 index 0000000000..b904e05d3a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarRule.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2020, dekvall + * Copyright (c) 2020, Jordan + * 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.herbiboars; + +import java.util.List; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +enum HerbiboarRule +{ + A_SOUTH(HerbiboarSearchSpot.Group.A, HerbiboarStart.MIDDLE), + C_WEST(HerbiboarSearchSpot.Group.C, HerbiboarStart.MIDDLE), + D_WEST_1(HerbiboarSearchSpot.Group.D, HerbiboarStart.MIDDLE), + D_WEST_2(HerbiboarSearchSpot.Group.D, HerbiboarSearchSpot.Group.C), + E_NORTH(HerbiboarSearchSpot.Group.E, HerbiboarSearchSpot.Group.A), + F_EAST(HerbiboarSearchSpot.Group.F, HerbiboarSearchSpot.Group.G), + G_NORTH(HerbiboarSearchSpot.Group.G, HerbiboarSearchSpot.Group.F), + H_NORTH(HerbiboarSearchSpot.Group.H, HerbiboarSearchSpot.Group.D), + H_EAST(HerbiboarSearchSpot.Group.H, HerbiboarStart.DRIFTWOOD), + I_EAST(HerbiboarSearchSpot.Group.I, HerbiboarStart.LEPRECHAUN), + I_SOUTH_1(HerbiboarSearchSpot.Group.I, HerbiboarStart.GHOST_MUSHROOM), + I_SOUTH_2(HerbiboarSearchSpot.Group.I, HerbiboarStart.CAMP_ENTRANCE), + I_WEST(HerbiboarSearchSpot.Group.I, HerbiboarSearchSpot.Group.E), + ; + + private final HerbiboarSearchSpot.Group to; + private final HerbiboarStart fromStart; + private final HerbiboarSearchSpot.Group fromGroup; + + HerbiboarRule(HerbiboarSearchSpot.Group to, HerbiboarSearchSpot.Group from) + { + this(to, null, from); + } + + HerbiboarRule(HerbiboarSearchSpot.Group to, HerbiboarStart fromStart) + { + this(to, fromStart, null); + } + + /** + * Returns whether the next {@link HerbiboarSearchSpot} can be deterministically selected based on the starting + * location and the path taken so far, based on the rules defined on the OSRS wiki. + * + * {@see https://oldschool.runescape.wiki/w/Herbiboar#Guaranteed_tracks} + * + * @param start Herbiboar's starting spot where the tracking path begins + * @param currentPath A list of {@link HerbiboarSearchSpot}s which have been searched thus far, and the next one to search + * @return {@code true} if a rule can be applied, {@code false} otherwise + */ + static boolean canApplyRule(HerbiboarStart start, List currentPath) + { + if (start == null || currentPath.isEmpty()) + { + return false; + } + + int lastIndex = currentPath.size() - 1; + HerbiboarSearchSpot.Group goingTo = currentPath.get(lastIndex).getGroup(); + + for (HerbiboarRule rule : values()) + { + if (lastIndex > 0 && rule.matches(currentPath.get(lastIndex - 1).getGroup(), goingTo) + || lastIndex == 0 && rule.matches(start, goingTo)) + { + return true; + } + } + + return false; + } + + boolean matches(HerbiboarStart from, HerbiboarSearchSpot.Group to) + { + return this.matches(from, null, to); + } + + boolean matches(HerbiboarSearchSpot.Group from, HerbiboarSearchSpot.Group to) + { + return this.matches(null, from, to); + } + + boolean matches(HerbiboarStart fromStart, HerbiboarSearchSpot.Group fromGroup, HerbiboarSearchSpot.Group to) + { + return this.to == to + && (fromStart != null && this.fromStart == fromStart || fromGroup != null && this.fromGroup == fromGroup); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarSearchSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarSearchSpot.java new file mode 100644 index 0000000000..9e324f5a2b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarSearchSpot.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2020, dekvall + * Copyright (c) 2020, Jordan + * 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.herbiboars; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.Getter; +import static net.runelite.api.NullObjectID.*; +import net.runelite.api.Varbits; +import net.runelite.api.coords.WorldPoint; + +@Getter +enum HerbiboarSearchSpot +{ + // Wiki A location + A_MUSHROOM(Group.A, new WorldPoint(3670, 3889, 0), + new TrailToSpot(Varbits.HB_TRAIL_31318, 1, NULL_31318), + new TrailToSpot(Varbits.HB_TRAIL_31321, 1, NULL_31321)), + A_PATCH(Group.A, new WorldPoint(3672, 3890, 0), + new TrailToSpot(Varbits.HB_TRAIL_31306, 2, NULL_31306)), + + // Wiki B location + B_SEAWEED(Group.B, new WorldPoint(3728, 3893, 0), + new TrailToSpot(Varbits.HB_TRAIL_31315, 2, NULL_31315), + new TrailToSpot(Varbits.HB_TRAIL_31318, 2, NULL_31318), + new TrailToSpot(Varbits.HB_TRAIL_31336, 1, NULL_31336), + new TrailToSpot(Varbits.HB_TRAIL_31339, 1, NULL_31339)), + + // Wiki C location + C_MUSHROOM(Group.C, new WorldPoint(3697, 3875, 0), + new TrailToSpot(Varbits.HB_TRAIL_31303, 2, NULL_31303)), + C_PATCH(Group.C, new WorldPoint(3699, 3875, 0), + new TrailToSpot(Varbits.HB_TRAIL_31312, 1, NULL_31312), + new TrailToSpot(Varbits.HB_TRAIL_31315, 1, NULL_31315)), + + // Wiki D location + D_PATCH(Group.D, new WorldPoint(3708, 3876, 0), + new TrailToSpot(Varbits.HB_TRAIL_31330, 1, NULL_31330), + new TrailToSpot(Varbits.HB_TRAIL_31333, 1, NULL_31333)), + D_SEAWEED(Group.D, new WorldPoint(3710, 3877, 0), + new TrailToSpot(Varbits.HB_TRAIL_31312, 2, NULL_31312), + new TrailToSpot(Varbits.HB_TRAIL_31339, 2, NULL_31339)), + + // Wiki E location + E_MUSHROOM(Group.E, new WorldPoint(3668, 3865, 0), + new TrailToSpot(Varbits.HB_TRAIL_31342, 1, NULL_31342), + new TrailToSpot(Varbits.HB_TRAIL_31345, 1, NULL_31345)), + E_PATCH(Group.E, new WorldPoint(3667, 3862, 0), + new TrailToSpot(Varbits.HB_TRAIL_31321, 2, NULL_31321)), + + // Wiki F location + F_MUSHROOM(Group.F, new WorldPoint(3681, 3860, 0), + new TrailToSpot(Varbits.HB_TRAIL_31324, 1, NULL_31324), + new TrailToSpot(Varbits.HB_TRAIL_31327, 1, NULL_31327), + new TrailToSpot(Varbits.HB_TRAIL_31342, 2, NULL_31342)), + F_PATCH(Group.F, new WorldPoint(3681, 3859, 0), + new TrailToSpot(Varbits.HB_TRAIL_31309, 2, NULL_31309)), + + // Wiki G location + G_MUSHROOM(Group.G, new WorldPoint(3694, 3847, 0), + new TrailToSpot(Varbits.HB_TRAIL_31333, 2, NULL_31333), + new TrailToSpot(Varbits.HB_TRAIL_31354, 1, NULL_31354)), + G_PATCH(Group.G, new WorldPoint(3698, 3847, 0), + new TrailToSpot(Varbits.HB_TRAIL_31327, 2, NULL_31327)), + + // Wiki H location + H_SEAWEED_EAST(Group.H, new WorldPoint(3715, 3851, 0), + new TrailToSpot(Varbits.HB_TRAIL_31357, 1, NULL_31357), + new TrailToSpot(Varbits.HB_TRAIL_31360, 1, NULL_31360)), + H_SEAWEED_WEST(Group.H, new WorldPoint(3713, 3850, 0), + new TrailToSpot(Varbits.HB_TRAIL_31330, 2, NULL_31330), + new TrailToSpot(Varbits.HB_TRAIL_31363, 1, NULL_31363)), + + // Wiki I location + I_MUSHROOM(Group.I, new WorldPoint(3680, 3838, 0), + new TrailToSpot(Varbits.HB_TRAIL_31348, 1, NULL_31348), + new TrailToSpot(Varbits.HB_TRAIL_31351, 1, NULL_31351)), + I_PATCH(Group.I, new WorldPoint(3680, 3836, 0), + new TrailToSpot(Varbits.HB_TRAIL_31324, 2, NULL_31324), + new TrailToSpot(Varbits.HB_TRAIL_31345, 2, NULL_31345)), + + // Wiki J location + J_PATCH(Group.J, new WorldPoint(3713, 3840, 0), + new TrailToSpot(Varbits.HB_TRAIL_31357, 2, NULL_31357), + new TrailToSpot(Varbits.HB_TRAIL_31372, 1, NULL_31372)), + + // Wiki K location + K_PATCH(Group.K, new WorldPoint(3706, 3811, 0), + new TrailToSpot(Varbits.HB_TRAIL_31348, 2, NULL_31348), + new TrailToSpot(Varbits.HB_TRAIL_31366, 1, NULL_31366), + new TrailToSpot(Varbits.HB_TRAIL_31369, 1, NULL_31369)), + ; + + private static final ImmutableMultimap GROUPS; + private static final Set SPOTS; + private static final Set TRAILS; + + static + { + ImmutableMultimap.Builder groupBuilder = new ImmutableMultimap.Builder<>(); + ImmutableSet.Builder spotBuilder = new ImmutableSet.Builder<>(); + ImmutableSet.Builder trailBuilder = new ImmutableSet.Builder<>(); + + for (HerbiboarSearchSpot spot : values()) + { + groupBuilder.put(spot.getGroup(), spot); + spotBuilder.add(spot.getLocation()); + + for (TrailToSpot trail : spot.getTrails()) + { + trailBuilder.addAll(trail.getFootprintIds()); + } + } + + GROUPS = groupBuilder.build(); + SPOTS = spotBuilder.build(); + TRAILS = trailBuilder.build(); + } + + private final Group group; + private final WorldPoint location; + private final List trails; + + HerbiboarSearchSpot(Group group, WorldPoint location, TrailToSpot... trails) + { + this.group = group; + this.location = location; + this.trails = ImmutableList.copyOf(trails); + } + + /** + * Spots are placed in groups of two + */ + enum Group + { + A, B, C, D, E, F, G, H, I, J, K + } + + static boolean isTrail(int id) + { + return TRAILS.contains(id); + } + + static boolean isSearchSpot(WorldPoint location) + { + return SPOTS.contains(location); + } + + static List getGroupLocations(Group group) + { + return GROUPS.get(group).stream().map(HerbiboarSearchSpot::getLocation).collect(Collectors.toList()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarStart.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarStart.java new file mode 100644 index 0000000000..3aa6485450 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarStart.java @@ -0,0 +1,55 @@ +/* + * 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.herbiboars; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.runelite.api.coords.WorldPoint; + +@Getter +@RequiredArgsConstructor +enum HerbiboarStart +{ + MIDDLE(new WorldPoint(3686, 3870, 0)), + LEPRECHAUN(new WorldPoint(3705, 3830, 0)), + CAMP_ENTRANCE(new WorldPoint(3704, 3810, 0)), + GHOST_MUSHROOM(new WorldPoint(3695, 3800, 0)), + DRIFTWOOD(new WorldPoint(3751, 3850, 0)), + ; + + private final WorldPoint location; + + static HerbiboarStart from(WorldPoint location) + { + for (final HerbiboarStart start : values()) + { + if (start.getLocation().equals(location)) + { + return start; + } + } + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarTrail.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarTrail.java deleted file mode 100644 index 6f1dba41fb..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarTrail.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2017, Tyler - * 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.herbiboars; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.runelite.api.Varbits; -import net.runelite.api.coords.WorldPoint; - -//Location of GameObjects which show TRAIL_xxxxx when used -@AllArgsConstructor -public enum HerbiboarTrail -{ - TRAIL_31303(31303, Varbits.HB_TRAIL_31303, null, new WorldPoint(3697, 3875, 0), null, new WorldPoint(3699, 3875, 0)), - TRAIL_31306(31306, Varbits.HB_TRAIL_31306, null, new WorldPoint(3672, 3890, 0), null, new WorldPoint(3670, 3889, 0)), - TRAIL_31309(31309, Varbits.HB_TRAIL_31309, null, new WorldPoint(3681, 3859, 0), null, new WorldPoint(3681, 3860, 0)), - TRAIL_31312(31312, Varbits.HB_TRAIL_31312, new WorldPoint(3699, 3875, 0), new WorldPoint(3710, 3877, 0), new WorldPoint(3697, 3875, 0), new WorldPoint(3708, 3876, 0)), - TRAIL_31315(31315, Varbits.HB_TRAIL_31315, new WorldPoint(3699, 3875, 0), new WorldPoint(3728, 3893, 0), new WorldPoint(3697, 3875, 0), null), - TRAIL_31318(31318, Varbits.HB_TRAIL_31318, new WorldPoint(3670, 3889, 0), new WorldPoint(3728, 3893, 0), new WorldPoint(3672, 3890, 0), null), - TRAIL_31321(31321, Varbits.HB_TRAIL_31321, new WorldPoint(3670, 3889, 0), new WorldPoint(3667, 3862, 0), new WorldPoint(3672, 3890, 0), new WorldPoint(3668, 3865, 0)), - TRAIL_31324(31324, Varbits.HB_TRAIL_31324, new WorldPoint(3681, 3860, 0), new WorldPoint(3680, 3836, 0), new WorldPoint(3681, 3859, 0), new WorldPoint(3680, 3838, 0)), - TRAIL_31327(31327, Varbits.HB_TRAIL_31327, new WorldPoint(3681, 3860, 0), new WorldPoint(3698, 3847, 0), new WorldPoint(3681, 3859, 0), new WorldPoint(3694, 3847, 0)), - TRAIL_31330(31330, Varbits.HB_TRAIL_31330, new WorldPoint(3708, 3876, 0), new WorldPoint(3713, 3850, 0), new WorldPoint(3710, 3877, 0), new WorldPoint(3715, 3851, 0)), - TRAIL_31333(31333, Varbits.HB_TRAIL_31333, new WorldPoint(3708, 3876, 0), new WorldPoint(3694, 3847, 0), new WorldPoint(3710, 3877, 0), new WorldPoint(3698, 3847, 0)), - TRAIL_31336(31336, Varbits.HB_TRAIL_31336, new WorldPoint(3728, 3893, 0), null, null, null), - TRAIL_31339(31339, Varbits.HB_TRAIL_31339, new WorldPoint(3728, 3893, 0), new WorldPoint(3710, 3877, 0), null, new WorldPoint(3708, 3876, 0)), - TRAIL_31342(31342, Varbits.HB_TRAIL_31342, new WorldPoint(3668, 3865, 0), new WorldPoint(3681, 3860, 0), new WorldPoint(3667, 3862, 0), new WorldPoint(3681, 3859, 0)), - TRAIL_31345(31345, Varbits.HB_TRAIL_31345, new WorldPoint(3668, 3865, 0), new WorldPoint(3680, 3836, 0), new WorldPoint(3667, 3862, 0), new WorldPoint(3680, 3838, 0)), - TRAIL_31348(31348, Varbits.HB_TRAIL_31348, new WorldPoint(3680, 3838, 0), new WorldPoint(3706, 3811, 0), new WorldPoint(3680, 3836, 0), null), - TRAIL_31351(31351, Varbits.HB_TRAIL_31351, new WorldPoint(3680, 3838, 0), null, new WorldPoint(3680, 3836, 0), null), - TRAIL_31354(31354, Varbits.HB_TRAIL_31354, new WorldPoint(3694, 3847, 0), null, new WorldPoint(3698, 3847, 0), null), - TRAIL_31357(31357, Varbits.HB_TRAIL_31357, new WorldPoint(3715, 3851, 0), new WorldPoint(3713, 3840, 0), new WorldPoint(3713, 3850, 0), null), - TRAIL_31360(31360, Varbits.HB_TRAIL_31360, new WorldPoint(3715, 3851, 0), null, new WorldPoint(3713, 3850, 0), null), - TRAIL_31363(31363, Varbits.HB_TRAIL_31363, new WorldPoint(3713, 3850, 0), null, new WorldPoint(3715, 3851, 0), null), - TRAIL_31366(31366, Varbits.HB_TRAIL_31366, null, null, null, null), - TRAIL_31369(31369, Varbits.HB_TRAIL_31369, new WorldPoint(3706, 3811, 0), null, null, null), - TRAIL_31372(31372, Varbits.HB_TRAIL_31372, new WorldPoint(3713, 3840, 0), null, null, null); - - @Getter - private final int trailId; - @Getter - private final Varbits varbit; - private final WorldPoint objectLoc1; - private final WorldPoint objectLoc2; - private final WorldPoint objectLoc3; - private final WorldPoint objectLoc4; - - @Getter - private static Set trailIds = new HashSet<>(); - @Getter - private static Set allObjectLocs = new HashSet<>(); - - static - { - for (HerbiboarTrail trail : values()) - { - trailIds.add(trail.trailId); - trailIds.add(trail.trailId + 1); - - allObjectLocs.addAll(Arrays.asList(trail.getObjectLocs(1))); - allObjectLocs.addAll(Arrays.asList(trail.getObjectLocs(2))); - } - } - - public WorldPoint[] getObjectLocs(int varbitValue) - { - switch (varbitValue) - { - case 1: - return new WorldPoint[]{objectLoc1, objectLoc3}; - case 2: - return new WorldPoint[]{objectLoc2, objectLoc4}; - case 0: - default: - return new WorldPoint[]{}; - } - } - - @Override - public String toString() - { - return String.format("trailId=%s obj1=%s obj2=%s obj3=%s obj4=%s", trailId, objectLoc1, objectLoc2, objectLoc3, objectLoc4); - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/TrailToSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/TrailToSpot.java new file mode 100644 index 0000000000..17c0b923cb --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/TrailToSpot.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020, dekvall + * Copyright (c) 2020, Jordan + * 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.herbiboars; + +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import lombok.Value; +import net.runelite.api.Varbits; + +/** + * A representation of a trail of footsteps which appears when hunting for the Herbiboar. + */ +@Value +class TrailToSpot +{ + /** + * The Varbit associated with the trail. When inactive, this Varbit's value should be less than + * {@link TrailToSpot#getValue()}. When this trail appears after searching a spot, this Varbit's value should be + * equal to that of {@link TrailToSpot#getValue()}. Once the next object along the trail has been searched, this + * Varbit's value will be greater than that of {@link TrailToSpot#getValue()}. + */ + private final Varbits varbit; + /** + * The cutoff reference value to compare against the value of {@link TrailToSpot#getVarbit()} to determine its state + * along the current trail. + */ + private final int value; + /** + * The object ID of the footprints which appear when the trail is made visible. + */ + private final int footprint; + + Set getFootprintIds() + { + return ImmutableSet.of(footprint, footprint + 1); + } +} From 544414a8cf406bcffb391ea912d9deeff0673f75 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 25 Mar 2020 12:55:20 -0400 Subject: [PATCH 06/11] clientloader: use fallback config if gamepack fails to load --- .../net/runelite/client/rs/ClientLoader.java | 90 ++++++++++++------- .../java/net/runelite/client/rs/RSConfig.java | 5 ++ 2 files changed, 62 insertions(+), 33 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java index 4309a10bbf..b52a19e937 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java @@ -49,12 +49,13 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.util.Arrays; import java.util.Collection; -import java.util.Map; import java.util.Enumeration; +import java.util.Map; import java.util.function.Supplier; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; +import javax.annotation.Nonnull; import javax.swing.SwingUtilities; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; @@ -66,9 +67,9 @@ import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA; import net.runelite.client.ui.FatalErrorDialog; import net.runelite.client.ui.SplashScreen; import net.runelite.client.util.CountingInputStream; +import net.runelite.client.util.VerificationException; import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.worlds.World; -import net.runelite.client.util.VerificationException; import okhttp3.HttpUrl; import okhttp3.Request; import okhttp3.Response; @@ -86,7 +87,6 @@ public class ClientLoader implements Supplier private Object client = null; private WorldSupplier worldSupplier = new WorldSupplier(); - private RSConfig config; public ClientLoader(ClientUpdateCheckMode updateCheckMode) { @@ -118,7 +118,7 @@ public class ClientLoader implements Supplier try { SplashScreen.stage(0, null, "Fetching applet viewer config"); - downloadConfig(); + RSConfig config = downloadConfig(); SplashScreen.stage(.05, null, "Waiting for other clients to start"); @@ -129,7 +129,24 @@ public class ClientLoader implements Supplier FileLock flock = lockfile.lock()) { SplashScreen.stage(.05, null, "Downloading Old School RuneScape"); - updateVanilla(); + try + { + updateVanilla(config); + } + catch (IOException ex) + { + // try again with the fallback config and gamepack + if (!config.isFallback()) + { + log.warn("Unable to download game client, attempting to use fallback config", ex); + config = downloadFallbackConfig(); + updateVanilla(config); + } + else + { + throw ex; + } + } if (updateCheckMode == AUTO) { @@ -146,7 +163,7 @@ public class ClientLoader implements Supplier SplashScreen.stage(.465, "Starting", "Starting Old School RuneScape"); - Applet rs = loadClient(classLoader); + Applet rs = loadClient(config, classLoader); SplashScreen.stage(.5, null, "Starting core classes"); @@ -162,7 +179,7 @@ public class ClientLoader implements Supplier } } - private void downloadConfig() throws IOException + private RSConfig downloadConfig() throws IOException { HttpUrl url = HttpUrl.parse(RuneLiteProperties.getJavConfig()); IOException err = null; @@ -170,14 +187,14 @@ public class ClientLoader implements Supplier { try { - config = ClientConfigLoader.fetch(url); + RSConfig config = ClientConfigLoader.fetch(url); if (Strings.isNullOrEmpty(config.getCodeBase()) || Strings.isNullOrEmpty(config.getInitialJar()) || Strings.isNullOrEmpty(config.getInitialClass())) { throw new IOException("Invalid or missing jav_config"); } - return; + return config; } catch (IOException e) { @@ -192,35 +209,42 @@ public class ClientLoader implements Supplier try { - RSConfig backupConfig = ClientConfigLoader.fetch(HttpUrl.parse(RuneLiteProperties.getJavConfigBackup())); - - if (Strings.isNullOrEmpty(backupConfig.getCodeBase()) || Strings.isNullOrEmpty(backupConfig.getInitialJar()) || Strings.isNullOrEmpty(backupConfig.getInitialClass())) - { - throw new IOException("Invalid or missing jav_config"); - } - - if (Strings.isNullOrEmpty(backupConfig.getRuneLiteGamepack()) || Strings.isNullOrEmpty(backupConfig.getRuneLiteWorldParam())) - { - throw new IOException("Backup config does not have RuneLite gamepack url"); - } - - // Randomize the codebase - World world = worldSupplier.get(); - backupConfig.setCodebase("http://" + world.getAddress() + "/"); - - // Update the world applet parameter - Map appletProperties = backupConfig.getAppletProperties(); - appletProperties.put(backupConfig.getRuneLiteWorldParam(), Integer.toString(world.getId())); - - config = backupConfig; + return downloadFallbackConfig(); } catch (IOException ex) { + log.debug("error downloading backup config", ex); throw err; // use error from Jagex's servers } } - private void updateVanilla() throws IOException, VerificationException + @Nonnull + private RSConfig downloadFallbackConfig() throws IOException + { + RSConfig backupConfig = ClientConfigLoader.fetch(HttpUrl.parse(RuneLiteProperties.getJavConfigBackup())); + + if (Strings.isNullOrEmpty(backupConfig.getCodeBase()) || Strings.isNullOrEmpty(backupConfig.getInitialJar()) || Strings.isNullOrEmpty(backupConfig.getInitialClass())) + { + throw new IOException("Invalid or missing jav_config"); + } + + if (Strings.isNullOrEmpty(backupConfig.getRuneLiteGamepack()) || Strings.isNullOrEmpty(backupConfig.getRuneLiteWorldParam())) + { + throw new IOException("Backup config does not have RuneLite gamepack url"); + } + + // Randomize the codebase + World world = worldSupplier.get(); + backupConfig.setCodebase("http://" + world.getAddress() + "/"); + + // Update the world applet parameter + Map appletProperties = backupConfig.getAppletProperties(); + appletProperties.put(backupConfig.getRuneLiteWorldParam(), Integer.toString(world.getId())); + + return backupConfig; + } + + private void updateVanilla(RSConfig config) throws IOException, VerificationException { Certificate[] jagexCertificateChain = getJagexCertificateChain(); @@ -256,7 +280,7 @@ public class ClientLoader implements Supplier // Start downloading the vanilla client HttpUrl url; - if (config.getRuneLiteGamepack() != null) + if (config.isFallback()) { // If we are using the backup config, use our own gamepack and ignore the codebase url = HttpUrl.parse(config.getRuneLiteGamepack()); @@ -503,7 +527,7 @@ public class ClientLoader implements Supplier } } - private Applet loadClient(ClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException, InstantiationException + private Applet loadClient(RSConfig config, ClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException, InstantiationException { String initialClass = config.getInitialClass(); Class clientClass = classLoader.loadClass(initialClass); diff --git a/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java b/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java index b1c43b14e9..cf7a46ad9d 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java @@ -55,6 +55,11 @@ class RSConfig return classLoaderProperties.get("initial_class").replace(".class", ""); } + boolean isFallback() + { + return getRuneLiteGamepack() != null; + } + String getRuneLiteGamepack() { return classLoaderProperties.get("runelite.gamepack"); From f6da67cd2de4fe908a6d6d9f0cec959bcc8b78fc Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 25 Mar 2020 13:19:25 -0400 Subject: [PATCH 07/11] clientloader: don't fallback to Jagex hostnames when using fallback config --- .../src/main/java/net/runelite/client/rs/ClientLoader.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java index b52a19e937..d06a55a499 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java @@ -390,7 +390,8 @@ public class ClientLoader implements Supplier { log.warn("Failed to download gamepack from \"{}\"", url, e); - if (attempt >= NUM_ATTEMPTS) + // With fallback config do 1 attempt (there are no additional urls to try) + if (config.isFallback() || attempt >= NUM_ATTEMPTS) { throw e; } From 2deadaed2e9df1fb600d1756f76e591df27d9b31 Mon Sep 17 00:00:00 2001 From: Trevor Date: Tue, 24 Mar 2020 13:05:44 -0400 Subject: [PATCH 08/11] spec counter plugin: fix other NPC hitsplats affecting specs --- .../specialcounter/SpecialCounterPlugin.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java index 562b263a17..946c4d2cde 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java @@ -61,7 +61,7 @@ public class SpecialCounterPlugin extends Plugin { private int currentWorld = -1; private int specialPercentage = -1; - private boolean specialUsed; + private NPC specedNPC; private SpecialWeapon specialWeapon; private final Set interactedNpcIds = new HashSet<>(); @@ -129,7 +129,11 @@ public class SpecialCounterPlugin extends Plugin this.specialPercentage = specialPercentage; this.specialWeapon = usedSpecialWeapon(); - specialUsed = true; + Actor interacting = client.getLocalPlayer().getInteracting(); + if (interacting instanceof NPC) + { + specedNPC = (NPC) interacting; + } } @Subscribe @@ -152,9 +156,9 @@ public class SpecialCounterPlugin extends Plugin addInteracting(interactingId); } - if (specialUsed) + if (specedNPC == hitsplatApplied.getActor()) { - specialUsed = false; + specedNPC = null; if (specialWeapon != null) { @@ -189,6 +193,12 @@ public class SpecialCounterPlugin extends Plugin { NPC actor = npcDespawned.getNpc(); + // if the NPC despawns before the hitsplat is shown + if (specedNPC == actor) + { + specedNPC = null; + } + if (actor.isDead() && interactedNpcIds.contains(actor.getId())) { removeCounters(); From 1d45b1474c61282266a866795c5bbc708396fe36 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 25 Mar 2020 18:08:41 -0400 Subject: [PATCH 09/11] boss timers: update Sarachnis time to 10 seconds --- .../main/java/net/runelite/client/plugins/bosstimer/Boss.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java index 3bd2cd68f5..f76348a7b7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java @@ -58,7 +58,7 @@ enum Boss KALPHITE_QUEEN(NpcID.KALPHITE_QUEEN_965, 30, ChronoUnit.SECONDS, ItemID.KALPHITE_PRINCESS), DUSK(NpcID.DUSK_7889, 2, ChronoUnit.MINUTES, ItemID.NOON), ALCHEMICAL_HYDRA(NpcID.ALCHEMICAL_HYDRA_8622, 25200, ChronoUnit.MILLIS, ItemID.IKKLE_HYDRA), - SARACHNIS(NpcID.SARACHNIS, 30, ChronoUnit.SECONDS, ItemID.SRARACHA), + SARACHNIS(NpcID.SARACHNIS, 10, ChronoUnit.SECONDS, ItemID.SRARACHA), ZALCANO(NpcID.ZALCANO_9050, 21600, ChronoUnit.MILLIS, ItemID.SMOLCANO); private static final Map bosses; From 11e21d7c77c159cac263f1a735604150fda756ab Mon Sep 17 00:00:00 2001 From: xKylee <48519776+xKylee@users.noreply.github.com> Date: Wed, 25 Mar 2020 22:48:48 +0000 Subject: [PATCH 10/11] up --- .../src/main/java/net/runelite/rs/api/RSWidget.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java index 589074b78b..251629b608 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java @@ -85,6 +85,9 @@ public interface RSWidget extends Widget @Import("modelType") int getModelType(); + + @Import("modelType") + void setModelType(int modelType); @Import("actions") @Override @@ -539,4 +542,4 @@ public interface RSWidget extends Widget @Import("onClick") @Override void setOnClickListener(Object[] o); -} +} \ No newline at end of file From 3518792b5fa7542eb3f157c8a4182d4acc77284d Mon Sep 17 00:00:00 2001 From: Kyle <48519776+xKylee@users.noreply.github.com> Date: Wed, 25 Mar 2020 23:41:04 +0000 Subject: [PATCH 11/11] Update RSWidget.java --- runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java index 251629b608..89b2a92d55 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java @@ -87,7 +87,7 @@ public interface RSWidget extends Widget int getModelType(); @Import("modelType") - void setModelType(int modelType); + void setModelType(int modelType); @Import("actions") @Override @@ -542,4 +542,4 @@ public interface RSWidget extends Widget @Import("onClick") @Override void setOnClickListener(Object[] o); -} \ No newline at end of file +}