From ab297e969cae932be8a654e915771991a508ffbc Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 16 Nov 2017 20:06:28 -0500 Subject: [PATCH 1/3] runelite-api: add MenuEntry abstraction for menu arrays --- .../main/java/net/runelite/api/Client.java | 7 +- .../main/java/net/runelite/api/MenuEntry.java | 102 ++++++++++++++++++ .../mousehighlight/MouseHighlightOverlay.java | 13 +-- .../net/runelite/mixins/RSClientMixin.java | 58 +++++++++- .../java/net/runelite/rs/api/RSClient.java | 30 ++++-- 5 files changed, 187 insertions(+), 23 deletions(-) create mode 100644 runelite-api/src/main/java/net/runelite/api/MenuEntry.java 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 e831b557c2..052a82ff0c 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -27,7 +27,6 @@ package net.runelite.api; import java.awt.Canvas; import java.util.List; import java.util.Map; - import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; @@ -107,11 +106,9 @@ public interface Client int[] getPlayerMenuTypes(); - String[] getMenuOptions(); + MenuEntry[] getMenuEntries(); - String[] getMenuTargets(); - - int getMenuOptionCount(); + void setMenuEntries(MenuEntry[] entries); boolean isMenuOpen(); diff --git a/runelite-api/src/main/java/net/runelite/api/MenuEntry.java b/runelite-api/src/main/java/net/runelite/api/MenuEntry.java new file mode 100644 index 0000000000..dccdfcf3dd --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/MenuEntry.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016-2017, 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.api; + +public class MenuEntry +{ + private String option; + private String target; + private int identifier; + private MenuAction type; + private int param0; + private int param1; + + @Override + public String toString() + { + return "MenuEntry{" + "option=" + option + ", target=" + target + ", identifier=" + identifier + ", type=" + type + ", param0=" + param0 + ", param1=" + param1 + '}'; + } + + public String getOption() + { + return option; + } + + public void setOption(String option) + { + this.option = option; + } + + public String getTarget() + { + return target; + } + + public void setTarget(String target) + { + this.target = target; + } + + public int getIdentifier() + { + return identifier; + } + + public void setIdentifier(int identifier) + { + this.identifier = identifier; + } + + public MenuAction getType() + { + return type; + } + + public void setType(MenuAction type) + { + this.type = type; + } + + public int getParam0() + { + return param0; + } + + public void setParam0(int param0) + { + this.param0 = param0; + } + + public int getParam1() + { + return param1; + } + + public void setParam1(int param1) + { + this.param1 = param1; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java index ad66991cb2..598113fa1c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java @@ -30,6 +30,7 @@ import javax.annotation.Nullable; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.MenuEntry; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayRenderer; @@ -67,17 +68,17 @@ class MouseHighlightOverlay extends Overlay return null; } - String[] targets = client.getMenuTargets(); - String[] options = client.getMenuOptions(); - int count = client.getMenuOptionCount() - 1; + MenuEntry[] menuEntries = client.getMenuEntries(); + int last = menuEntries.length - 1; - if (count < 0 || count >= targets.length || count >= options.length) + if (last < 0) { return null; } - String target = targets[count]; - String option = options[count]; + MenuEntry menuEntry = menuEntries[last]; + String target = menuEntry.getTarget(); + String option = menuEntry.getOption(); if (target.isEmpty()) { diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java index 5923815905..e62763c8cc 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -27,6 +27,8 @@ package net.runelite.mixins; import java.util.ArrayList; import java.util.List; import net.runelite.api.GameState; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; import net.runelite.api.NPC; import net.runelite.api.Player; import net.runelite.api.Point; @@ -51,12 +53,12 @@ public abstract class RSClientMixin implements RSClient int[] playerIndexes = getPlayerIndices(); Player[] cachedPlayers = getCachedPlayers(); List players = new ArrayList(validPlayerIndexes); - + for (int i = 0; i < validPlayerIndexes; ++i) { players.add(cachedPlayers[playerIndexes[i]]); } - + return players; } @@ -260,4 +262,56 @@ public abstract class RSClientMixin implements RSClient } return getWidget(WidgetInfo.FIXED_VIEWPORT); } + + @Inject + @Override + public MenuEntry[] getMenuEntries() + { + int count = getMenuOptionCount(); + String[] menuOptions = getMenuOptions(); + String[] menuTargets = getMenuTargets(); + int[] menuIdentifiers = getMenuIdentifiers(); + int[] menuTypes = getMenuTypes(); + int[] params0 = getMenuActionParams0(); + int[] params1 = getMenuActionParams1(); + + MenuEntry[] entries = new MenuEntry[count]; + for (int i = 0; i < count; ++i) + { + MenuEntry entry = entries[i] = new MenuEntry(); + entry.setOption(menuOptions[i]); + entry.setTarget(menuTargets[i]); + entry.setIdentifier(menuIdentifiers[i]); + entry.setType(MenuAction.of(menuTypes[i])); + entry.setParam0(params0[i]); + entry.setParam1(params1[i]); + } + return entries; + } + + @Inject + @Override + public void setMenuEntries(MenuEntry[] entries) + { + int count = 0; + String[] menuOptions = getMenuOptions(); + String[] menuTargets = getMenuTargets(); + int[] menuIdentifiers = getMenuIdentifiers(); + int[] menuTypes = getMenuTypes(); + int[] params0 = getMenuActionParams0(); + int[] params1 = getMenuActionParams1(); + + for (MenuEntry entry : entries) + { + menuOptions[count] = entry.getOption(); + menuTargets[count] = entry.getTarget(); + menuIdentifiers[count] = entry.getIdentifier(); + menuTypes[count] = entry.getType().getId(); + params0[count] = entry.getParam0(); + params1[count] = entry.getParam1(); + ++count; + } + + setMenuOptionCount(count); + } } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index 82bf381673..6605856945 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -162,14 +162,6 @@ public interface RSClient extends RSGameEngine, Client @Override int[] getPlayerMenuTypes(); - @Import("menuTargets") - @Override - String[] getMenuTargets(); - - @Import("menuOptions") - @Override - String[] getMenuOptions(); - @Import("mouseX") int getMouseX(); @@ -179,12 +171,30 @@ public interface RSClient extends RSGameEngine, Client @Import("menuOptionCount") int getMenuOptionCount(); - @Import("menuTypes") - int[] getMenuTypes(); + @Import( + value = "menuOptionCount", + setter = true + ) + void setMenuOptionCount(int menuOptionCount); + + @Import("menuOptions") + String[] getMenuOptions(); + + @Import("menuTargets") + String[] getMenuTargets(); @Import("menuIdentifiers") int[] getMenuIdentifiers(); + @Import("menuTypes") + int[] getMenuTypes(); + + @Import("menuActionParams0") + int[] getMenuActionParams0(); + + @Import("menuActionParams1") + int[] getMenuActionParams1(); + @Import("friends") RSFriend[] getFriends(); From c7a0699a4186df98080e3fb9876b2e18ceffd66a Mon Sep 17 00:00:00 2001 From: Toocanzs Date: Thu, 16 Nov 2017 20:11:19 -0500 Subject: [PATCH 2/3] menu manager: add custom widget menu capability --- .../net/runelite/api/widgets/WidgetInfo.java | 7 ++ .../net/runelite/client/callback/Hooks.java | 18 ++- .../client/events/MenuEntryAdded.java | 75 +++++++++++++ .../client/events/MenuOptionClicked.java | 11 ++ .../events/WidgetMenuOptionClicked.java | 64 +++++++++++ .../runelite/client/menus/MenuManager.java | 90 +++++++++++++++ .../client/menus/WidgetMenuOption.java | 105 ++++++++++++++++++ 7 files changed, 368 insertions(+), 2 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/events/MenuEntryAdded.java create mode 100644 runelite-client/src/main/java/net/runelite/client/events/WidgetMenuOptionClicked.java create mode 100644 runelite-client/src/main/java/net/runelite/client/menus/WidgetMenuOption.java diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index 5533ae61b1..ba6fe27ed5 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -28,6 +28,8 @@ public enum WidgetInfo { INVENTORY(WidgetID.INVENTORY_GROUP_ID, 0), + WORLD_MAP(WidgetID.WORLD_MAP_MENU_GROUP_ID, WidgetID.WorldMap.OPTION), + CLUE_SCROLL_TEXT(WidgetID.CLUE_SCROLL_GROUP_ID, WidgetID.Cluescroll.CLUE_TEXT), EQUIPMENT(WidgetID.EQUIPMENT_GROUP_ID, 0), @@ -106,6 +108,11 @@ public enum WidgetInfo this.childId = childId; } + public int getId() + { + return groupId << 16 | childId; + } + public int getGroupId() { return groupId; 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 8806a2f3c0..325c9ced50 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 @@ -176,7 +176,7 @@ public class Hooks } } - public static void menuActionHook(int var0, int var1, int menuAction, int id, String menuOption, String menuTarget, int var6, int var7) + public static void menuActionHook(int var0, int widgetId, int menuAction, int id, String menuOption, String menuTarget, int var6, int var7) { /* Along the way, the RuneScape client may change a menuAction by incrementing it with 2000. * I have no idea why, but it does. Their code contains the same conditional statement. @@ -186,17 +186,31 @@ public class Hooks menuAction -= 2000; } - logger.debug("Menu action clicked: {} ({}) on {} ({})", menuOption, menuAction, menuTarget.isEmpty() ? "" : menuTarget, id); + logger.debug("Menu action clicked: {} ({}) on {} ({} widget: {})", + menuOption, menuAction, menuTarget.isEmpty() ? "" : menuTarget, id, var0, widgetId); MenuOptionClicked menuOptionClicked = new MenuOptionClicked(); menuOptionClicked.setMenuOption(menuOption); menuOptionClicked.setMenuTarget(menuTarget); menuOptionClicked.setMenuAction(MenuAction.of(menuAction)); menuOptionClicked.setId(id); + menuOptionClicked.setWidgetId(widgetId); eventBus.post(menuOptionClicked); } + public static void addMenuEntry(String option, String target, int type, int identifier, int param0, int param1) + { + if (logger.isTraceEnabled()) + { + logger.trace("Menu entry added {} {}", option, target); + } + + MenuEntryAdded menuEntry = new MenuEntryAdded(option, target, type, identifier, param0, param1); + + eventBus.post(menuEntry); + } + public static void addChatMessage(int type, String sender, String message, String clan) { if (logger.isDebugEnabled()) diff --git a/runelite-client/src/main/java/net/runelite/client/events/MenuEntryAdded.java b/runelite-client/src/main/java/net/runelite/client/events/MenuEntryAdded.java new file mode 100644 index 0000000000..6e8e225cfa --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/events/MenuEntryAdded.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, 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.events; + +public class MenuEntryAdded +{ + private String option; + private String target; + private int type; + private int identifier; + private int actionParam0; + private int actionParam1; + + public MenuEntryAdded(String option, String target, int type, int identifier, int actionParam0, int param1) + { + this.option = option; + this.target = target; + this.type = type; + this.identifier = identifier; + this.actionParam0 = actionParam0; + this.actionParam1 = param1; + } + + public String getOption() + { + return option; + } + + public String getTarget() + { + return target; + } + + public int getType() + { + return type; + } + + public int getIdentifier() + { + return identifier; + } + + public int getActionParam0() + { + return actionParam0; + } + + public int getActionParam1() + { + return actionParam1; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/events/MenuOptionClicked.java b/runelite-client/src/main/java/net/runelite/client/events/MenuOptionClicked.java index 24a277a70c..b228954f20 100644 --- a/runelite-client/src/main/java/net/runelite/client/events/MenuOptionClicked.java +++ b/runelite-client/src/main/java/net/runelite/client/events/MenuOptionClicked.java @@ -36,6 +36,7 @@ public class MenuOptionClicked private String menuTarget; private MenuAction menuAction; private int id; + private int widgetId; public String getMenuOption() { @@ -77,4 +78,14 @@ public class MenuOptionClicked this.id = id; } + public int getWidgetId() + { + return widgetId; + } + + public void setWidgetId(int widgetId) + { + this.widgetId = widgetId; + } + } diff --git a/runelite-client/src/main/java/net/runelite/client/events/WidgetMenuOptionClicked.java b/runelite-client/src/main/java/net/runelite/client/events/WidgetMenuOptionClicked.java new file mode 100644 index 0000000000..2ab2ebc860 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/events/WidgetMenuOptionClicked.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017, 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.events; + +import net.runelite.api.widgets.WidgetInfo; + +public class WidgetMenuOptionClicked +{ + private String menuOption; + private String menuTarget; + private WidgetInfo widget; + + public String getMenuOption() + { + return menuOption; + } + + public void setMenuOption(String menuOption) + { + this.menuOption = menuOption; + } + + public String getMenuTarget() + { + return menuTarget; + } + + public void setMenuTarget(String menuTarget) + { + this.menuTarget = menuTarget; + } + + public WidgetInfo getWidget() + { + return widget; + } + + public void setWidget(WidgetInfo widget) + { + this.widget = widget; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/menus/MenuManager.java b/runelite-client/src/main/java/net/runelite/client/menus/MenuManager.java index ec78f7224b..4e64361c20 100644 --- a/runelite-client/src/main/java/net/runelite/client/menus/MenuManager.java +++ b/runelite-client/src/main/java/net/runelite/client/menus/MenuManager.java @@ -25,8 +25,12 @@ package net.runelite.client.menus; import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; @@ -34,6 +38,10 @@ import javax.inject.Provider; import javax.inject.Singleton; import net.runelite.api.Client; import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.events.WidgetMenuOptionClicked; +import net.runelite.client.events.MenuEntryAdded; import net.runelite.client.events.MenuOptionClicked; import net.runelite.client.events.PlayerMenuOptionClicked; import net.runelite.client.events.PlayerMenuOptionsChanged; @@ -56,6 +64,8 @@ public class MenuManager //Maps the indexes that are being used to the menu option. private final Map playerMenuIndexMap = new HashMap<>(); + //Used to manage custom non-player menu options + private final Multimap managedMenuOptions = HashMultimap.create(); @Inject public MenuManager(Provider clientProvider, EventBus eventBus) @@ -64,6 +74,69 @@ public class MenuManager this.eventBus = eventBus; } + /** + * Adds a CustomMenuOption to the list of managed menu options. + * + * @param customMenuOption The custom menu to add + */ + public void addManagedCustomMenu(WidgetMenuOption customMenuOption) + { + WidgetInfo widget = customMenuOption.getWidget(); + managedMenuOptions.put(widget.getId(), customMenuOption); + } + + /** + * Removes a CustomMenuOption from the list of managed menu options. + * + * @param customMenuOption The custom menu to add + */ + public void removeManagedCustomMenu(WidgetMenuOption customMenuOption) + { + WidgetInfo widget = customMenuOption.getWidget(); + managedMenuOptions.remove(widget.getId(), customMenuOption); + } + + private boolean menuContainsCustomMenu(WidgetMenuOption customMenuOption) + { + Client client = clientProvider.get(); + for (MenuEntry menuEntry : client.getMenuEntries()) + { + String option = menuEntry.getOption(); + String target = menuEntry.getTarget(); + + if (option.equals(customMenuOption.getMenuOption()) && target.equals(customMenuOption.getMenuTarget())) + { + return true; + } + } + return false; + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + int widgetId = event.getActionParam1(); + Collection options = managedMenuOptions.get(widgetId); + for (WidgetMenuOption currentMenu : options) + { + Client client = clientProvider.get(); + + if (!menuContainsCustomMenu(currentMenu))//Don't add if we have already added it to this widget + { + MenuEntry[] menuEntries = client.getMenuEntries(); + menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1); + + MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); + menuEntry.setOption(currentMenu.getMenuOption()); + menuEntry.setParam1(widgetId); + menuEntry.setTarget(currentMenu.getMenuTarget()); + menuEntry.setType(MenuAction.RUNELITE); + + client.setMenuEntries(menuEntries); + } + } + } + public void addPlayerMenuItem(String menuText) { Preconditions.checkNotNull(menuText); @@ -110,6 +183,23 @@ public class MenuManager return; // not a player menu } + int widgetId = event.getWidgetId(); + Collection options = managedMenuOptions.get(widgetId); + + for (WidgetMenuOption curMenuOption : options) + { + if (curMenuOption.getMenuTarget().equals(event.getMenuTarget()) + && curMenuOption.getMenuOption().equals(event.getMenuOption())) + { + WidgetMenuOptionClicked customMenu = new WidgetMenuOptionClicked(); + customMenu.setMenuOption(event.getMenuOption()); + customMenu.setMenuTarget(event.getMenuTarget()); + customMenu.setWidget(curMenuOption.getWidget()); + eventBus.post(customMenu); + return; // don't continue because it's not a player option + } + } + String target = event.getMenuTarget(); String username = target.split("[<>]")[2]; // username (level-42) diff --git a/runelite-client/src/main/java/net/runelite/client/menus/WidgetMenuOption.java b/runelite-client/src/main/java/net/runelite/client/menus/WidgetMenuOption.java new file mode 100644 index 0000000000..3f87509c83 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/menus/WidgetMenuOption.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017, Robin + * 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.menus; + +import net.runelite.api.widgets.WidgetInfo; + +import java.awt.Color; + +public final class WidgetMenuOption +{ + /** + * The left hand text to be displayed on the menu option. Ex. the menuOption of "Drop Bones" is "Drop" + */ + private String menuOption; + /** + * The right hand text to be displayed on the menu option Ex. the menuTarget of "Drop Bones" is "Bones" + */ + private String menuTarget; + /** + * The color that the menuTarget should be. Defaults to the brownish color that most menu options have. + */ + private Color color = Color.decode("#ff9040"); + + /** + * The widget to add the option to + */ + private final WidgetInfo widget; + + /** + * Creates a menu to be added to right click menus. The menu will only be added if match is found within the menu options + * + * @param menuOption Option text of this right click option + * @param menuTarget Target text of this right click option + * @param widget The widget to attach this option to + */ + public WidgetMenuOption(String menuOption, String menuTarget, WidgetInfo widget) + { + this.menuOption = menuOption; + setMenuTarget(menuTarget); + this.widget = widget; + } + + public void setMenuOption(String option) + { + menuOption = option; + } + + /** + * Sets the target of the menu option. Color code will be added on to target + * + * @param target The target text without color code. + */ + public void setMenuTarget(String target) + { + menuTarget = String.format("%s", + color.getRed(), color.getGreen(), color.getBlue(), target); + } + + public String getMenuOption() + { + return menuOption; + } + + public String getMenuTarget() + { + return menuTarget; + } + + public WidgetInfo getWidget() + { + return widget; + } + + public Color getColor() + { + return color; + } + + public void setColor(Color col) + { + color = col; + } +} From b6527df5fcdabed9459d2a8d8dcf6ee662a1c037 Mon Sep 17 00:00:00 2001 From: Toocanzs Date: Thu, 16 Nov 2017 20:11:48 -0500 Subject: [PATCH 3/3] runelite-client: add instance world map plugin --- .../java/net/runelite/api/SceneTilePaint.java | 30 +++++ .../src/main/java/net/runelite/api/Tile.java | 2 + .../net/runelite/api/widgets/WidgetID.java | 6 + .../instancemap/InstanceMapConfig.java | 47 +++++++ .../instancemap/InstanceMapOverlay.java | 114 +++++++++++++++++ .../plugins/instancemap/IntanceMapPlugin.java | 120 ++++++++++++++++++ .../net/runelite/rs/api/RSSceneTilePaint.java | 35 +++++ .../main/java/net/runelite/rs/api/RSTile.java | 5 + 8 files changed, 359 insertions(+) create mode 100644 runelite-api/src/main/java/net/runelite/api/SceneTilePaint.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapConfig.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/instancemap/IntanceMapPlugin.java create mode 100644 runescape-api/src/main/java/net/runelite/rs/api/RSSceneTilePaint.java diff --git a/runelite-api/src/main/java/net/runelite/api/SceneTilePaint.java b/runelite-api/src/main/java/net/runelite/api/SceneTilePaint.java new file mode 100644 index 0000000000..d9ab226d15 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/SceneTilePaint.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, 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.api; + +public interface SceneTilePaint +{ + int getRBG(); +} diff --git a/runelite-api/src/main/java/net/runelite/api/Tile.java b/runelite-api/src/main/java/net/runelite/api/Tile.java index ee1899a948..bc82e97274 100644 --- a/runelite-api/src/main/java/net/runelite/api/Tile.java +++ b/runelite-api/src/main/java/net/runelite/api/Tile.java @@ -40,4 +40,6 @@ public interface Tile GroundObject getGroundObject(); WallObject getWallObject(); + + SceneTilePaint getSceneTilePaint(); } diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index 0fdaeb2a6b..3bb39c4487 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -47,6 +47,12 @@ class WidgetID static final int SLAYER_REWARDS_GROUP_ID = 426; static final int PRIVATE_CHAT = 163; static final int CHATBOX_GROUP_ID = 162; + static final int WORLD_MAP_MENU_GROUP_ID = 160; + + static class WorldMap + { + static final int OPTION = 29; + } static class SlayerRewards { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapConfig.java new file mode 100644 index 0000000000..c91ba50005 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapConfig.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, 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.instancemap; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup( + keyName = "instancemap", + name = "Instance Map", + description = "Displays a map of the current instance" +) +public interface InstanceMapConfig extends Config +{ + @ConfigItem( + keyName = "enabled", + name = "Enabled", + description = "Enables or disables the overlay" + ) + default boolean enabled() + { + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java new file mode 100644 index 0000000000..27d2167e1a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017, 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.instancemap; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.annotation.Nullable; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.Tile; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; + +class InstanceMapOverlay extends Overlay +{ + /** + * Size of the drawn tile in the instance map. + */ + private static final int tileSize = 3; + + private final Client client; + private final InstanceMapConfig config; + + private boolean showMap = false; + + @Inject + InstanceMapOverlay(@Nullable Client client, + InstanceMapConfig config) + { + super(OverlayPosition.DYNAMIC); + this.client = client; + this.config = config; + } + + public boolean isMapShown() + { + return showMap; + } + + public void setShowMap(boolean show) + { + showMap = show; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (client.getGameState() != GameState.LOGGED_IN || !config.enabled() || !showMap) + { + return null; + } + + return drawInstanceMap(graphics); + } + + /** + * Draws all the tiles on the current plane of client.reigion to the + * screen. This will show instances unlike the world map. + * + * @param graphics graphics to draw to + * @return The dimensions of the map + */ + private Dimension drawInstanceMap(Graphics2D graphics) + { + Tile[][][] regionTiles = client.getRegion().getTiles(); + + int plane = client.getPlane(); + Tile[][] tiles = regionTiles[plane]; + + Dimension mapOverlaySize = new Dimension(tiles.length * tileSize, tiles[0].length * tileSize); + + graphics.setColor(Color.BLACK); + graphics.fillRect(0, 0, mapOverlaySize.width, mapOverlaySize.height); + + for (int x = 0; x < tiles.length; x++) + { + for (int y = 0; y < tiles[x].length; y++) + { + Tile curTile = tiles[x][(tiles[x].length - 1) - y]; // flip the y value + if (curTile != null && curTile.getSceneTilePaint() != null) + { + graphics.setColor(new Color(curTile.getSceneTilePaint().getRBG())); + graphics.fillRect(x * tileSize, y * tileSize, tileSize, tileSize); + } + } + } + + return mapOverlaySize; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/IntanceMapPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/IntanceMapPlugin.java new file mode 100644 index 0000000000..b8083d1adb --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/IntanceMapPlugin.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017, 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.instancemap; + +import com.google.common.eventbus.Subscribe; +import com.google.inject.Binder; +import com.google.inject.Provides; +import javax.inject.Inject; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.events.ConfigChanged; +import net.runelite.client.events.WidgetMenuOptionClicked; +import net.runelite.client.menus.WidgetMenuOption; +import net.runelite.client.menus.MenuManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.Overlay; + +@PluginDescriptor( + name = "Instance Map" +) +public class IntanceMapPlugin extends Plugin +{ + private final WidgetMenuOption openMapOption = new WidgetMenuOption("Show", "Instance Map", WidgetInfo.WORLD_MAP); + + @Inject + InstanceMapConfig config; + + @Inject + InstanceMapOverlay overlay; + + @Inject + MenuManager menuManager; + + @Override + public void configure(Binder binder) + { + binder.bind(InstanceMapOverlay.class); + } + + @Provides + InstanceMapConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(InstanceMapConfig.class); + } + + @Override + protected void startUp() throws Exception + { + if (config.enabled()) + { + menuManager.addManagedCustomMenu(openMapOption); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (config.enabled()) + { + menuManager.addManagedCustomMenu(openMapOption); + } + else + { + menuManager.removeManagedCustomMenu(openMapOption); + } + } + + @Subscribe + public void onWidgetMenuOptionClicked(WidgetMenuOptionClicked event) + { + if (!config.enabled()) + { + return; + } + + if (event.getMenuOption().equals(openMapOption.getMenuOption()) + && event.getMenuTarget().equals(openMapOption.getMenuTarget()) + && event.getWidget() == WidgetInfo.WORLD_MAP) + { + overlay.setShowMap(!overlay.isMapShown()); + if (overlay.isMapShown()) + { + openMapOption.setMenuOption("Hide"); + } + else + { + openMapOption.setMenuOption("Show"); + } + } + } + + @Override + public Overlay getOverlay() + { + return overlay; + } +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSSceneTilePaint.java b/runescape-api/src/main/java/net/runelite/rs/api/RSSceneTilePaint.java new file mode 100644 index 0000000000..30d61a5ab2 --- /dev/null +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSSceneTilePaint.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016-2017, 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.rs.api; + +import net.runelite.api.SceneTilePaint; +import net.runelite.mapping.Import; + +public interface RSSceneTilePaint extends SceneTilePaint +{ + @Import("rgb") + @Override + int getRBG(); +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSTile.java b/runescape-api/src/main/java/net/runelite/rs/api/RSTile.java index 9ba477cdbc..a4c58722f2 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSTile.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSTile.java @@ -28,6 +28,7 @@ import net.runelite.api.DecorativeObject; import net.runelite.api.GameObject; import net.runelite.api.GroundObject; import net.runelite.api.ItemLayer; +import net.runelite.api.SceneTilePaint; import net.runelite.api.Tile; import net.runelite.api.WallObject; import net.runelite.mapping.Import; @@ -54,6 +55,10 @@ public interface RSTile extends Tile @Override WallObject getWallObject(); + @Import("paint") + @Override + SceneTilePaint getSceneTilePaint(); + @Import("x") int getX();