From 35e6e341bb9db6bbe8dab17e7bacfde709bbcdc9 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Mon, 26 Nov 2018 19:33:30 -0700 Subject: [PATCH] Add Wiki plugin This has the side affect of making the click mask around the run orb correct in fixed mode --- .../main/java/net/runelite/api/Client.java | 5 + .../main/java/net/runelite/api/SpriteID.java | 2 +- .../java/net/runelite/api/widgets/Widget.java | 52 +++ .../runelite/api/widgets/WidgetConfig.java | 51 +++ .../net/runelite/api/widgets/WidgetID.java | 9 + .../net/runelite/api/widgets/WidgetInfo.java | 7 +- .../devtools/WidgetInfoTableModel.java | 3 + .../client/plugins/wiki/WikiPlugin.java | 289 +++++++++++++++++ .../wiki/WikiSearchChatboxTextInput.java | 302 ++++++++++++++++++ .../client/plugins/wiki/WikiSprite.java | 44 +++ .../wiki/fixed_mode_minimap_clickmask.png | Bin 0 -> 2027 bytes .../net/runelite/client/plugins/wiki/wiki.png | Bin 0 -> 3092 bytes .../client/plugins/wiki/wiki_selected.png | Bin 0 -> 3025 bytes .../java/net/runelite/rs/api/RSClient.java | 4 + .../java/net/runelite/rs/api/RSWidget.java | 36 +++ 15 files changed, 802 insertions(+), 2 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSprite.java create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/wiki/fixed_mode_minimap_clickmask.png create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/wiki/wiki.png create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/wiki/wiki_selected.png 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 ca51dc74a9..652eb00806 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1569,4 +1569,9 @@ public interface Client extends GameEngine int getRasterizer3D_clipMidY2(); void checkClickbox(Model model, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash); + + /** + * Sets if a widget is in target mode + */ + void setSpellSelected(boolean selected); } diff --git a/runelite-api/src/main/java/net/runelite/api/SpriteID.java b/runelite-api/src/main/java/net/runelite/api/SpriteID.java index 2c4ac4f878..e707854c12 100644 --- a/runelite-api/src/main/java/net/runelite/api/SpriteID.java +++ b/runelite-api/src/main/java/net/runelite/api/SpriteID.java @@ -1172,7 +1172,7 @@ public final class SpriteID public static final int MINIMAP_ORB_XP_ACTIVATED = 1197; public static final int MINIMAP_ORB_XP_HOVERED = 1198; public static final int MINIMAP_ORB_XP_ACTIVATED_HOVERED = 1199; - public static final int UNKNOWN_BLACK_BLOBS = 1200; + public static final int MINIMAP_CLICK_MASK = 1200; public static final int OPTIONS_ZOOM_SLIDER_THUMB = 1201; public static final int EMOTE_SIT_UP = 1202; public static final int EMOTE_STAR_JUMP = 1203; 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 3aa6e23f13..ed4277a2a3 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 @@ -79,6 +79,7 @@ public interface Widget /** * Gets the current click configuration of the widget. + * @see WidgetConfig * * @see WidgetConfig */ @@ -551,6 +552,13 @@ public interface Widget */ void setOnMouseOverListener(Object... args); + /** + * Sets a script to be ran every frame when the mouse is in the widget bounds + * + * @param args A ScriptID, then the args for the script + */ + void setOnMouseRepeatListener(Object... args); + /** * Sets a script to be ran when the mouse leaves the widget bounds * @@ -565,6 +573,20 @@ public interface Widget */ void setOnTimerListener(Object... args); + /** + * Sets a script to be ran when the target mode has been activated for this widget + * + * @param args A ScriptID, then the args for the script + */ + void setOnTargetEnterListener(Object... args); + + /** + * Sets a script to be ran when the target mode has been deactivated for this widget + * + * @param args A ScriptID, then the args for the script + */ + void setOnTargetLeaveListener(Object... args); + /** * If this widget has any listeners on it */ @@ -769,4 +791,34 @@ public interface Widget * Sets if the rectangle is filled or just stroked */ void setFilled(boolean filled); + + /** + * Verb for spell targets + */ + String getTargetVerb(); + + /** + * Verb for spell targets + */ + void setTargetVerb(String targetVerb); + + /** + * Can widgets under this widgets be clicked in this widgets bounding box + */ + boolean getNoClickThrough(); + + /** + * Can widgets under this widgets be clicked in this widgets bounding box + */ + void setNoClickThrough(boolean noClickThrough); + + /** + * Can widgets under this widgets be scrolled in this widgets bounding box + */ + boolean getNoScrollThrough(); + + /** + * Can widgets under this widgets be scrolled in this widgets bounding box + */ + void setNoScrollThrough(boolean noScrollThrough); } diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetConfig.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetConfig.java index 0b8f6a587d..31829b5417 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetConfig.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetConfig.java @@ -24,6 +24,8 @@ */ package net.runelite.api.widgets; +import net.runelite.api.MenuAction; + /** * Utility class used for defining options to be used on the click mask * of a {@link Widget}. @@ -36,12 +38,61 @@ public class WidgetConfig * Enables displaying a ninth option on a menu. */ public static final int SHOW_MENU_OPTION_NINE = 1 << 9; + + /** + * Can this widget be used on a item on the floor + */ + public static final int USE_GROUND_ITEM = 1 << 11; + + /** + * Can this widget be used on a NPC + */ + public static final int USE_NPC = 2 << 11; + + /** + * Can this widget be used on a game object + */ + public static final int USE_OBJECT = 4 << 11; + + /** + * Can this widget be used on a player + */ + public static final int USE_PLAYER = 8 << 11; + + /** + * Can this widget be used on a item in your inventory + */ + public static final int USE_ITEM = 16 << 11; + + /** + * Can this widget be used on a widget with the WIDGET_USE_TARGET flag + */ + public static final int USE_WIDGET = 32 << 11; + /** * Controls whether or not a widget can have another dragged onto it. */ public static final int DRAG_ON = 1 << 17; + /** * Controls whether or not a widget can be dragged around. */ public static final int DRAG = 1 << 20; + + /** + * Can widgets with USE_WIDGET be used on this widget + */ + public static final int WIDGET_USE_TARGET = 1 << 21; + + /** + * Is the widget an (inventory?) item + */ + public static final int ITEM = 1 << 30; + + /** + * Add a USE option + * + * @see MenuAction#ITEM_USE + */ + public static final int ITEM_USE_OP = 1 << 31; } 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 9f07f9ba37..e919c0f992 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 @@ -125,6 +125,7 @@ public class WidgetID public static final int SKOTIZO_GROUP_ID = 308; public static final int ENTERING_HOUSE_GROUP_ID = 71; public static final int FULLSCREEN_MAP_GROUP_ID = 165; + public static final int QUESTLIST_GROUP_ID = 399; static class WorldMap { @@ -292,6 +293,7 @@ public class WidgetID static final int TOGGLE_RUN_ORB = 22; // Has the "Toggle run" name static final int RUN_ORB_TEXT = 23; static final int SPEC_ORB = 28; + static final int WORLDMAP_ORB = 40; } static class LoginClickToPlayScreen @@ -747,4 +749,11 @@ public class WidgetID { static final int ROOT = 25; } + + static class QuestList + { + static final int FREE_CONTAINER = 9; + static final int MEMBERS_CONTAINER = 10; + static final int MINIQUEST_CONTAINER = 11; + } } 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 556dc57bf5..7808e06cba 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 @@ -159,6 +159,7 @@ public enum WidgetInfo MINIMAP_RUN_ORB_TEXT(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.RUN_ORB_TEXT), MINIMAP_HEALTH_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.HEALTH_ORB), MINIMAP_SPEC_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.SPEC_ORB), + MINIMAP_WORLDMAP_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.WORLDMAP_ORB), LOGIN_CLICK_TO_PLAY_SCREEN(WidgetID.LOGIN_CLICK_TO_PLAY_GROUP_ID, 0), LOGIN_CLICK_TO_PLAY_SCREEN_MESSAGE_OF_THE_DAY(WidgetID.LOGIN_CLICK_TO_PLAY_GROUP_ID, WidgetID.LoginClickToPlayScreen.MESSAGE_OF_THE_DAY), @@ -463,7 +464,11 @@ public enum WidgetInfo SKOTIZO_CONTAINER(WidgetID.SKOTIZO_GROUP_ID, WidgetID.Skotizo.CONTAINER), - FULLSCREEN_MAP_ROOT(WidgetID.FULLSCREEN_MAP_GROUP_ID, WidgetID.FullScreenMap.ROOT); + FULLSCREEN_MAP_ROOT(WidgetID.FULLSCREEN_MAP_GROUP_ID, WidgetID.FullScreenMap.ROOT), + + QUESTLIST_FREE_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.FREE_CONTAINER), + QUESTLIST_MEMBERS_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.MEMBERS_CONTAINER), + QUESTLIST_MINIQUEST_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.MINIQUEST_CONTAINER); private final int groupId; private final int childId; 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 79bb99bc5a..acd8851c0b 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 @@ -183,6 +183,9 @@ public class WidgetInfoTableModel extends AbstractTableModel out.add(new WidgetField<>("ScrollHeight", Widget::getScrollHeight, Widget::setScrollHeight, Integer.class)); out.add(new WidgetField<>("DragDeadZone", Widget::getDragDeadZone, Widget::setDragDeadZone, Integer.class)); out.add(new WidgetField<>("DragDeadTime", Widget::getDragDeadTime, Widget::setDragDeadTime, Integer.class)); + out.add(new WidgetField<>("NoClickThrough", Widget::getNoClickThrough, Widget::setNoClickThrough, Boolean.class)); + out.add(new WidgetField<>("NoScrollThrough", Widget::getNoScrollThrough, Widget::setNoScrollThrough, Boolean.class)); + out.add(new WidgetField<>("TargetVerb", Widget::getTargetVerb, Widget::setTargetVerb, String.class)); return out; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java new file mode 100644 index 0000000000..e6b21437e0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiPlugin.java @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2018 Abex + * 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.wiki; + +import com.google.common.primitives.Ints; +import java.net.URLEncoder; +import java.util.Arrays; +import javax.inject.Inject; +import javax.inject.Provider; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.NPC; +import net.runelite.api.NPCComposition; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetConfig; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetPositionMode; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.game.chatbox.ChatboxPanelManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.LinkBrowser; +import net.runelite.client.util.Text; +import okhttp3.HttpUrl; + +@Slf4j +@PluginDescriptor( + name = "Wiki", + description = "Adds a Wiki button that takes you to the OSRS Wiki" +) +public class WikiPlugin extends Plugin +{ + private static final int[] QUESTLIST_WIDGET_IDS = new int[] + { + WidgetInfo.QUESTLIST_FREE_CONTAINER.getId(), + WidgetInfo.QUESTLIST_MEMBERS_CONTAINER.getId(), + WidgetInfo.QUESTLIST_MINIQUEST_CONTAINER.getId(), + }; + + static final String WIKI_BASE = "https://oldschool.runescape.wiki"; + static final HttpUrl WIKI_RSLOOKUP = HttpUrl.parse(WIKI_BASE + "/w/Special:Lookup"); + static final HttpUrl WIKI_API = HttpUrl.parse(WIKI_BASE + "/api.php"); + static final String UTM_SORUCE_KEY = "utm_source"; + static final String UTM_SORUCE_VALUE = "runelite"; + static final String UTM_PARAMS = UTM_SORUCE_KEY + "=" + UTM_SORUCE_VALUE; + + private static final String MENUOP_GUIDE = "Guide"; + private static final String MENUOP_QUICKGUIDE = "Quick Guide"; + + @Inject + private SpriteManager spriteManager; + + @Inject + private ClientThread clientThread; + + @Inject + private Client client; + + @Inject + private ChatboxPanelManager chatboxPanelManager; + + @Inject + private ItemManager itemManager; + + @Inject + private Provider wikiSearchChatboxTextInputProvider; + + private Widget icon; + + private boolean wikiSelected = false; + + @Override + public void startUp() + { + spriteManager.addSpriteOverrides(WikiSprite.values()); + clientThread.invokeLater(this::addWidgets); + } + + @Override + public void shutDown() + { + spriteManager.removeSpriteOverrides(WikiSprite.values()); + clientThread.invokeLater(() -> + { + Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS); + if (minimapOrbs == null) + { + return; + } + Widget[] children = minimapOrbs.getChildren(); + if (children == null || children.length < 1) + { + return; + } + children[0] = null; + }); + } + + @Subscribe + private void onWidgetLoaded(WidgetLoaded l) + { + if (l.getGroupId() == WidgetID.MINIMAP_GROUP_ID) + { + addWidgets(); + } + } + + private void addWidgets() + { + Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS); + if (minimapOrbs == null) + { + return; + } + + icon = minimapOrbs.createChild(0, WidgetType.GRAPHIC); + icon.setSpriteId(WikiSprite.WIKI_ICON.getSpriteId()); + icon.setOriginalX(0); + icon.setOriginalY(2); + icon.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); + icon.setYPositionMode(WidgetPositionMode.ABSOLUTE_BOTTOM); + icon.setOriginalWidth(42); + icon.setOriginalHeight(16); + icon.setTargetVerb("Lookup"); + icon.setName("Wiki"); + icon.setClickMask(WidgetConfig.USE_GROUND_ITEM | WidgetConfig.USE_ITEM | WidgetConfig.USE_NPC); + icon.setNoClickThrough(true); + icon.setOnTargetEnterListener((JavaScriptCallback) ev -> + { + wikiSelected = true; + icon.setSpriteId(WikiSprite.WIKI_SELECTED_ICON.getSpriteId()); + }); + icon.setAction(5, "Search"); // Start at option 5 so the target op is ontop + icon.setOnOpListener((JavaScriptCallback) ev -> + { + switch (ev.getOp()) + { + case 6: + openSearchInput(); + break; + } + }); + // This doesn't always run because we cancel the menuop + icon.setOnTargetLeaveListener((JavaScriptCallback) ev -> onDeselect()); + icon.revalidate(); + } + + private void onDeselect() + { + wikiSelected = false; + icon.setSpriteId(WikiSprite.WIKI_ICON.getSpriteId()); + } + + @Subscribe + private void onMenuOptionClicked(MenuOptionClicked ev) + { + if (wikiSelected) + { + onDeselect(); + client.setSpellSelected(false); + ev.consume(); + + String type; + int id; + String name; + switch (ev.getMenuAction()) + { + case CANCEL: + return; + case ITEM_USE_ON_WIDGET: + case SPELL_CAST_ON_GROUND_ITEM: + { + type = "item"; + id = itemManager.canonicalize(ev.getId()); + name = itemManager.getItemComposition(id).getName(); + break; + } + case SPELL_CAST_ON_NPC: + { + type = "npc"; + NPC npc = client.getCachedNPCs()[ev.getId()]; + NPCComposition nc = npc.getTransformedComposition(); + id = nc.getId(); + name = nc.getName(); + break; + } + default: + log.info("Unknown menu option: {} {} {}", ev, ev.getMenuAction(), ev.getMenuAction() == MenuAction.CANCEL); + return; + } + + HttpUrl url = WIKI_RSLOOKUP.newBuilder() + .addQueryParameter("type", type) + .addQueryParameter("id", "" + id) + .addQueryParameter("name", name) + .addQueryParameter(UTM_SORUCE_KEY, UTM_SORUCE_VALUE) + .build(); + + LinkBrowser.browse(url.toString()); + return; + } + + if (ev.getMenuAction() == MenuAction.RUNELITE) + { + String quickguide = ""; + switch (ev.getMenuOption()) + { + case MENUOP_QUICKGUIDE: + quickguide = "/Quick_guide"; + //fallthrough; + case MENUOP_GUIDE: + ev.consume(); + String quest = Text.removeTags(ev.getMenuTarget()); + LinkBrowser.browse(WIKI_BASE + "/w/" + URLEncoder.encode(quest.replace(' ', '_')) + quickguide + "?" + UTM_PARAMS); + break; + } + } + } + + private void openSearchInput() + { + wikiSearchChatboxTextInputProvider.get() + .build(); + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + int widgetIndex = event.getActionParam0(); + int widgetID = event.getActionParam1(); + + if (!Ints.contains(QUESTLIST_WIDGET_IDS, widgetID) || !"Read Journal:".equals(event.getOption())) + { + return; + } + + MenuEntry[] menuEntries = client.getMenuEntries(); + menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 2); + + MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); + menuEntry.setTarget(event.getTarget()); + menuEntry.setOption(MENUOP_GUIDE); + menuEntry.setParam0(widgetIndex); + menuEntry.setParam1(widgetID); + menuEntry.setType(MenuAction.RUNELITE.getId()); + + menuEntry = menuEntries[menuEntries.length - 2] = new MenuEntry(); + menuEntry.setTarget(event.getTarget()); + menuEntry.setOption(MENUOP_QUICKGUIDE); + menuEntry.setParam0(widgetIndex); + menuEntry.setParam1(widgetID); + menuEntry.setType(MenuAction.RUNELITE.getId()); + + client.setMenuEntries(menuEntries); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java new file mode 100644 index 0000000000..51ea075d2f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2018 Abex + * 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.wiki; + +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import com.google.inject.Inject; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import javax.inject.Named; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetPositionMode; +import net.runelite.api.widgets.WidgetSizeMode; +import net.runelite.api.widgets.WidgetTextAlignment; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.game.chatbox.ChatboxPanelManager; +import net.runelite.client.game.chatbox.ChatboxTextInput; +import net.runelite.client.util.LinkBrowser; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; + +@Slf4j +public class WikiSearchChatboxTextInput extends ChatboxTextInput +{ + private static final int LINE_HEIGHT = 20; + private static final int CHATBOX_HEIGHT = 120; + private static final int MAX_NUM_PREDICTIONS = (CHATBOX_HEIGHT / LINE_HEIGHT) - 2; // 1 title, 1 edit + + private static final int PREDICTION_DEBOUNCE_DELAY_MS = 200; + + private final ChatboxPanelManager chatboxPanelManager; + private final Gson gson = new Gson(); + + private Future runningRequest = null; + private List predictions = ImmutableList.of(); + + private int selectedPrediction = -1; + private String offPrediction = null; + + @Inject + public WikiSearchChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread, + ScheduledExecutorService scheduledExecutorService, @Named("developerMode") final boolean developerMode) + { + super(chatboxPanelManager, clientThread); + this.chatboxPanelManager = chatboxPanelManager; + + prompt("OSRS Wiki Search"); + onDone(string -> + { + if (string != null && string.length() > 0) + { + search(string); + } + }); + onChanged(searchString -> + { + selectedPrediction = -1; + Future rr = runningRequest; + if (rr != null) + { + rr.cancel(false); + } + if (searchString.length() <= 1) + { + runningRequest = null; + clientThread.invokeLater(() -> + { + predictions = ImmutableList.of(); + update(); + }); + return; + } + runningRequest = scheduledExecutorService.schedule(() -> + { + HttpUrl url = WikiPlugin.WIKI_API.newBuilder() + .addQueryParameter("action", "opensearch") + .addQueryParameter("search", searchString) + .addQueryParameter("redirects", "resolve") + .addQueryParameter("format", "json") + .addQueryParameter("warningsaserror", Boolean.toString(developerMode)) + .build(); + + Request req = new Request.Builder() + .url(url) + .build(); + + RuneLiteAPI.CLIENT.newCall(req).enqueue(new Callback() + { + @Override + public void onFailure(Call call, IOException e) + { + log.warn("error searching wiki", e); + } + + @Override + public void onResponse(Call call, Response response) throws IOException + { + String body = response.body().string(); + try + { + JsonArray jar = new JsonParser().parse(body).getAsJsonArray(); + List apredictions = gson.fromJson(jar.get(1), new TypeToken>() + { + }.getType()); + + if (apredictions.size() > MAX_NUM_PREDICTIONS) + { + apredictions = apredictions.subList(0, MAX_NUM_PREDICTIONS); + } + + final List bpredictions = apredictions; + + clientThread.invokeLater(() -> + { + predictions = bpredictions; + update(); + }); + } + catch (JsonParseException | IllegalStateException | IndexOutOfBoundsException e) + { + log.warn("error parsing wiki response {}", body, e); + } + finally + { + response.close(); + } + } + }); + + runningRequest = null; + }, PREDICTION_DEBOUNCE_DELAY_MS, TimeUnit.MILLISECONDS); + }); + } + + @Override + protected void update() + { + Widget container = chatboxPanelManager.getContainerWidget(); + container.deleteAllChildren(); + + Widget promptWidget = container.createChild(-1, WidgetType.TEXT); + promptWidget.setText(getPrompt()); + promptWidget.setTextColor(0x800000); + promptWidget.setFontId(getFontID()); + promptWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); + promptWidget.setOriginalX(0); + promptWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + promptWidget.setOriginalY(5); + promptWidget.setOriginalHeight(LINE_HEIGHT); + promptWidget.setXTextAlignment(WidgetTextAlignment.CENTER); + promptWidget.setYTextAlignment(WidgetTextAlignment.CENTER); + promptWidget.setWidthMode(WidgetSizeMode.MINUS); + promptWidget.revalidate(); + + buildEdit(0, 5 + LINE_HEIGHT, container.getWidth(), LINE_HEIGHT); + + Widget separator = container.createChild(-1, WidgetType.LINE); + separator.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); + separator.setOriginalX(0); + separator.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + separator.setOriginalY(4 + (LINE_HEIGHT * 2)); + separator.setOriginalHeight(0); + separator.setOriginalWidth(16); + separator.setWidthMode(WidgetSizeMode.MINUS); + separator.revalidate(); + + for (int i = 0; i < predictions.size(); i++) + { + String pred = predictions.get(i); + int y = 6 + (LINE_HEIGHT * (2 + i)); + + Widget bg = container.createChild(-1, WidgetType.RECTANGLE); + bg.setTextColor(0x4444DD); + bg.setFilled(true); + bg.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); + bg.setOriginalX(1); + bg.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + bg.setOriginalY(y); + bg.setOriginalHeight(LINE_HEIGHT); + bg.setOriginalWidth(16); + bg.setWidthMode(WidgetSizeMode.MINUS); + bg.revalidate(); + bg.setName("" + pred); + bg.setAction(0, "Open"); + bg.setHasListener(true); + bg.setOnOpListener((JavaScriptCallback) ev -> search(pred)); + + Widget text = container.createChild(-1, WidgetType.TEXT); + text.setText(pred); + text.setFontId(getFontID()); + text.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); + text.setOriginalX(0); + text.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + text.setOriginalY(y); + text.setOriginalHeight(LINE_HEIGHT); + text.setXTextAlignment(WidgetTextAlignment.CENTER); + text.setYTextAlignment(WidgetTextAlignment.CENTER); + text.setWidthMode(WidgetSizeMode.MINUS); + text.revalidate(); + + if (i == selectedPrediction) + { + text.setTextColor(0xFFFFFF); + } + else + { + bg.setOpacity(255); + text.setTextColor(0x000000); + bg.setOnMouseRepeatListener((JavaScriptCallback) ev -> text.setTextColor(0xFFFFFF)); + bg.setOnMouseLeaveListener((JavaScriptCallback) ev -> text.setTextColor(0x000000)); + } + } + } + + @Override + public void keyPressed(KeyEvent ev) + { + switch (ev.getKeyCode()) + { + case KeyEvent.VK_UP: + ev.consume(); + if (selectedPrediction > -1) + { + selectedPrediction--; + if (selectedPrediction == -1) + { + value(offPrediction); + } + else + { + value(predictions.get(selectedPrediction)); + } + } + break; + case KeyEvent.VK_DOWN: + ev.consume(); + + if (selectedPrediction == -1) + { + offPrediction = getValue(); + } + + selectedPrediction++; + if (selectedPrediction >= predictions.size()) + { + selectedPrediction = predictions.size() - 1; + } + + if (selectedPrediction != -1) + { + value(predictions.get(selectedPrediction)); + } + break; + default: + super.keyPressed(ev); + } + } + + private void search(String search) + { + LinkBrowser.browse(WikiPlugin.WIKI_BASE + "?search=" + URLEncoder.encode(search) + "&" + WikiPlugin.UTM_PARAMS); + chatboxPanelManager.close(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSprite.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSprite.java new file mode 100644 index 0000000000..188d54837b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSprite.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Abex + * 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.wiki; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.runelite.api.SpriteID; +import net.runelite.client.game.SpriteOverride; + +@RequiredArgsConstructor +public enum WikiSprite implements SpriteOverride +{ + WIKI_ICON(-300, "wiki.png"), + WIKI_SELECTED_ICON(-301, "wiki_selected.png"), + FIXED_MODE_MINIMAP_CLICKMASK(SpriteID.MINIMAP_CLICK_MASK, "fixed_mode_minimap_clickmask.png"); + + @Getter + private final int spriteId; + + @Getter + private final String fileName; +} diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/wiki/fixed_mode_minimap_clickmask.png b/runelite-client/src/main/resources/net/runelite/client/plugins/wiki/fixed_mode_minimap_clickmask.png new file mode 100644 index 0000000000000000000000000000000000000000..e4f5fcbe48dab813a165f99d60a28acb3c4cb4ec GIT binary patch literal 2027 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 literal 0 HcmV?d00001 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/wiki/wiki_selected.png b/runelite-client/src/main/resources/net/runelite/client/plugins/wiki/wiki_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..80838fb5c4f5f4406f0570212fb7e9825664b7ee GIT binary patch literal 3025 zcmcIm3s@6Z8V#VxLoA?(unHkytCq=|yh;>EKq5pbusp;ElbHzwl1#`1608)#7b=1l z7b>(A5d|Mu1XNg-mx9=86(4AqsuZo7x+se%MHJi#uXVfXy8C^bFO!+M_uO;O`Tzgk zn{7eMms(jkS`Y{XE0Mo27{4#VFKaVX{5P8PXcvAnSNTU`1cK#E!(~Ls|7s3_V0uy( z8lj002l60PK?Y$|f{=9z6^ih!P}5rsR`)>l#T!8O$ezdx)uGl>mvA z`L9zWA?uchLhIroE=*donCPkF;RFgq0}^!#xf0{)_@q%@9{y}-rjUrE5KTOvMdi|&?nFA3#->o&6dD7d(s)!BkHIC5e@OUjYFNq( z7W$3Pg}?Dhu^NqvN1D#p z#m8j#q#G4aphiFqst!d_`9z|ECRm690dYaNObMe}Y@tEVI2;jz8iY^6bH)K^G=ROb7rOY!JZP5GoyHND!uER2M#8h(d{m;2Fk`6)lWHILBms zc#ssLO1MlZz~$1|02^Y$0GGkWtx6eeiB!U1Nm$YewiRj_zHUJI>#PPe;I~nIC*>-g&+yzPjVS? zv^IGlWLOe>5@e_a1SX9)%ia*?_cJs`tBpl)(sxwJ7z{(D8ZD?sykqc`{D&H(yiGa= zCcRrY6JgOk*dBOBIS2x9U?u|qsS*(2a6LF|CY#HZcpwwT{|~~)Lkh)$$`}OSTPdXf z-OBrw`df1F`^ER)=itp&D25GnthOk>FT2sc*EU}~iK9*Uj&69IJWBAF$-@Xy;!#rL zN6nE-3u+03Da|6Gcc_0`M{cUWByv`pYr2_@i;r7|wT;kc(=Ia?q1&zuGm?+7%{DKg z(AwO_+pW0u)}Jy?9JKNH&ZLuuT)N5Ax4>1m$hv+2W>zWw^D@^i~nsl}z!r0%oZpG?Us zGRkq_C400Upfs7z3+rq;*3#42Z*;g)9ouXz7A@3ZoFc!jOjQcWru=Sbnps!Amw zef3>8pPcOv?YVchJEy!tMBL=j^>-KX?ymX8seE}8=Z;%#?qc1uvi-%jNsqUZYDzzH zNO3$Va*VznH#ILf#r$E|A<*^bORE))#ZFLB`i!XC+8d$;r)p-HmIQkdiWaEjTHuU$ z_=@G7r-OxQl#&6~jc+#D8`tHpB)2p9%cPY1b1MG2IKcSEu)6ox0q4)Ra(C-SIG!1V z<+a9P4Nj-ILj_lb^79`mHpr?R=86vo1nsYB(DN4>cjWHzZhvliZJ}+*@_lAo>?|Uj zRCIPquIG*idK`7f-LA5OeR@x`&Z^qkS$}W1BhV(+NL|t3G!*wd&~jGV zGU`*$d23q-zs<;LaZJc<*gB$O<&4x;mCVggD7;{EKH{;1Ywm5gV}jXFUR;o=ho9#nx9x&(tK;XPwR*I=3q6HaUKSdCDb^c83e957z3cJm>k6KDr=vT{hpn@rSaz zKv_6>nmBUmU}C=8+3dp7J1)K>VV&B9!ZpbHgL#8c{;Qa&aGi6SV)^kXME9)q)&b<*;&D21yBDzHf(18@$Hs5ro#o9 z+y6%P=F=UjpTuJ=$wQ^*?mW%1hK~3Abo_@PVRj|dwr24s+ZEBzAM_5?1v?$s9{6bS zXL~wtnSW3gS}Waj-Zo~C__MeTYJ6c;&s`DlaiHVQS^EnDYb}eC_E761(lu zwEE6JZl<>$PLF%KcZxoF{Vu3?$K|e6+t1U0%F2561Fy)lTV`Af_}XiFTKcS<3v`gk=-Jp>yYA}UD2Um(w#Qn z++5zj8z)pIB{j_r!hT(g0B06!)@7Lq+&_0 fO4qLVCVkjy5t=M<8GgCO@TXhkyIgq8Cp!Hfq9Brt literal 0 HcmV?d00001 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 04ac90d398..23c2558a16 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 @@ -921,4 +921,8 @@ public interface RSClient extends RSGameEngine, Client @Import("endY") int getEndY(); + + @Import("spellSelected") + @Override + void setSpellSelected(boolean selected); } 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 75315b0514..0dd5b24d4f 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 @@ -328,6 +328,10 @@ public interface RSWidget extends Widget @Override void setOnMouseOverListener(Object... args); + @Import("onMouseRepeatListener") + @Override + void setOnMouseRepeatListener(Object... args); + @Import("onMouseLeaveListener") @Override void setOnMouseLeaveListener(Object... args); @@ -336,6 +340,14 @@ public interface RSWidget extends Widget @Override void setOnTimerListener(Object... args); + @Import("onTargetEnterListener") + @Override + void setOnTargetEnterListener(Object... args); + + @Import("onTargetLeaveListener") + @Override + void setOnTargetLeaveListener(Object... args); + @Import("fontId") @Override int getFontId(); @@ -435,4 +447,28 @@ public interface RSWidget extends Widget @Import("filled") @Override void setFilled(boolean filled); + + @Import("targetVerb") + @Override + String getTargetVerb(); + + @Import("targetVerb") + @Override + void setTargetVerb(String targetVerb); + + @Import("noClickThrough") + @Override + boolean getNoClickThrough(); + + @Import("noClickThrough") + @Override + void setNoClickThrough(boolean noClickThrough); + + @Import("noScrollThrough") + @Override + boolean getNoScrollThrough(); + + @Import("noScrollThrough") + @Override + void setNoScrollThrough(boolean noScrollThrough); }