diff --git a/runelite-api/src/main/java/net/runelite/api/VarPlayer.java b/runelite-api/src/main/java/net/runelite/api/VarPlayer.java index 414ed46de9..69a6a82377 100644 --- a/runelite-api/src/main/java/net/runelite/api/VarPlayer.java +++ b/runelite-api/src/main/java/net/runelite/api/VarPlayer.java @@ -273,9 +273,12 @@ public enum VarPlayer QUEST_ENTER_THE_ABYSS(492), QUEST_ALFRED_GRIMHANDS_BARCRAWL(77), QUEST_ALFRED_GRIMHANDS_BARCRAWL_STATE_76(76), - QUEST_THE_MAGE_ARENA(267); - + QUEST_THE_MAGE_ARENA(267), + /** + * 0 = 2 buttons, 1 = 1 button + */ + MOUSE_BUTTONS(170); public final int id; } diff --git a/runelite-client/runelite-client.gradle.kts b/runelite-client/runelite-client.gradle.kts index 9870c3187f..ac22c81790 100644 --- a/runelite-client/runelite-client.gradle.kts +++ b/runelite-client/runelite-client.gradle.kts @@ -89,10 +89,11 @@ dependencies { testImplementation(Libraries.guiceGrapher) testImplementation(Libraries.guiceTestlib) - testImplementation(Libraries.junit) testImplementation(Libraries.hamcrest) + testImplementation(Libraries.junit) testImplementation(Libraries.mockitoCore) testImplementation(Libraries.mockitoInline) + testImplementation(Libraries.okhttp3Webserver) testImplementation(Libraries.slf4jApi) } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java similarity index 80% rename from runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomConfig.java rename to runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java index 8934606590..fc6a20c676 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java @@ -22,7 +22,7 @@ * (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.zoom; +package net.runelite.client.plugins.camera; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; @@ -30,7 +30,7 @@ import net.runelite.client.config.ConfigItem; import net.runelite.client.config.Range; @ConfigGroup("zoom") -public interface ZoomConfig extends Config +public interface CameraConfig extends Config { int OUTER_LIMIT_MIN = -400; int OUTER_LIMIT_MAX = 400; @@ -115,4 +115,36 @@ public interface ZoomConfig extends Config return 25; } + @ConfigItem( + keyName = "rightClickMovesCamera", + name = "Right click moves camera", + description = "Remaps right click to middle mouse click if there are no menu options", + position = 7 + ) + default boolean rightClickMovesCamera() + { + return false; + } + + @ConfigItem( + keyName = "ignoreExamine", + name = "Ignore Examine", + description = "Ignore the Examine menu entry", + position = 8 + ) + default boolean ignoreExamine() + { + return false; + } + + @ConfigItem( + keyName = "middleClickMenu", + name = "Middle-button opens menu", + description = "Middle-mouse button always opens the menu", + position = 9 + ) + default boolean middleClickMenu() + { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java new file mode 100644 index 0000000000..71a6f5b8bf --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2018 Abex + * Copyright (c) 2018, Adam + * Copyright (c) 2019, Wynadorn + * 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.camera; + +import com.google.inject.Inject; +import com.google.inject.Provides; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import javax.swing.SwingUtilities; +import net.runelite.api.Client; +import net.runelite.api.MenuEntry; +import net.runelite.api.ScriptID; +import net.runelite.api.VarPlayer; +import net.runelite.api.events.ClientTick; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; +import net.runelite.client.input.KeyListener; +import net.runelite.client.input.KeyManager; +import net.runelite.client.input.MouseListener; +import net.runelite.client.input.MouseManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.MiscUtils; + +@PluginDescriptor( + name = "Camera Zoom", + description = "Expands zoom limit, provides vertical camera, and remaps mouse input keys", + tags = {"zoom", "limit", "vertical", "click", "mouse"}, + enabledByDefault = false +) +public class CameraPlugin extends Plugin implements KeyListener, MouseListener +{ + /** + * The largest (most zoomed in) value that can be used without the client crashing. + *

+ * Larger values trigger an overflow in the engine's fov to scale code. + */ + private static final int INNER_ZOOM_LIMIT = 1004; + private static final int DEFAULT_ZOOM_INCREMENT = 25; + + private boolean controlDown; + // flags used to store the mousedown states + private boolean rightClick; + private boolean middleClick; + /** + * Whether or not the current menu has any non-ignored menu entries + */ + private boolean menuHasEntries; + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private CameraConfig cameraConfig; + + @Inject + private KeyManager keyManager; + + @Inject + private MouseManager mouseManager; + + @Provides + CameraConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(CameraConfig.class); + } + + @Subscribe + private void onScriptCallbackEvent(ScriptCallbackEvent event) + { + if (client.getIndexScripts().isOverlayOutdated()) + { + // if any cache overlay fails to load then assume at least one of the zoom scripts is outdated + // and prevent zoom extending entirely. + return; + } + + int[] intStack = client.getIntStack(); + int intStackSize = client.getIntStackSize(); + + if (!controlDown && "scrollWheelZoom".equals(event.getEventName()) && cameraConfig.controlFunction() == ControlFunction.CONTROL_TO_ZOOM) + { + intStack[intStackSize - 1] = 1; + } + + if ("innerZoomLimit".equals(event.getEventName()) && cameraConfig.innerLimit()) + { + intStack[intStackSize - 1] = INNER_ZOOM_LIMIT; + return; + } + + if ("outerZoomLimit".equals(event.getEventName())) + { + int outerLimit = MiscUtils.clamp(cameraConfig.outerLimit(), CameraConfig.OUTER_LIMIT_MIN, CameraConfig.OUTER_LIMIT_MAX); + int outerZoomLimit = 128 - outerLimit; + intStack[intStackSize - 1] = outerZoomLimit; + return; + } + + if ("scrollWheelZoomIncrement".equals(event.getEventName()) && cameraConfig.zoomIncrement() != DEFAULT_ZOOM_INCREMENT) + { + intStack[intStackSize - 1] = cameraConfig.zoomIncrement(); + return; + } + + if (cameraConfig.innerLimit()) + { + // This lets the options panel's slider have an exponential rate + final double exponent = 2.d; + switch (event.getEventName()) + { + case "zoomLinToExp": + { + double range = intStack[intStackSize - 1]; + double value = intStack[intStackSize - 2]; + value = Math.pow(value / range, exponent) * range; + intStack[intStackSize - 2] = (int) value; + break; + } + case "zoomExpToLin": + { + double range = intStack[intStackSize - 1]; + double value = intStack[intStackSize - 2]; + value = Math.pow(value / range, 1.d / exponent) * range; + intStack[intStackSize - 2] = (int) value; + break; + } + } + } + } + + @Subscribe + private void onFocusChanged(FocusChanged event) + { + if (!event.isFocused()) + { + controlDown = false; + } + } + + @Override + protected void startUp() + { + rightClick = false; + middleClick = false; + menuHasEntries = false; + + client.setCameraPitchRelaxerEnabled(cameraConfig.relaxCameraPitch()); + keyManager.registerKeyListener(this); + mouseManager.registerMouseListener(this); + } + + @Override + protected void shutDown() + { + client.setCameraPitchRelaxerEnabled(false); + keyManager.unregisterKeyListener(this); + mouseManager.unregisterMouseListener(this); + controlDown = false; + } + + @Subscribe + private void onConfigChanged(ConfigChanged ev) + { + client.setCameraPitchRelaxerEnabled(cameraConfig.relaxCameraPitch()); + } + + @Override + public void keyTyped(KeyEvent e) + { + } + + @Override + public void keyPressed(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_CONTROL) + { + controlDown = true; + } + } + + @Override + public void keyReleased(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_CONTROL) + { + controlDown = false; + + if (cameraConfig.controlFunction() == ControlFunction.CONTROL_TO_RESET) + { + final int zoomValue = MiscUtils.clamp(cameraConfig.ctrlZoomValue(), cameraConfig.OUTER_LIMIT_MIN, INNER_ZOOM_LIMIT); + clientThread.invokeLater(() -> client.runScript(ScriptID.CAMERA_DO_ZOOM, zoomValue, zoomValue)); + } + } + } + + /** + * Checks if the menu has any non-ignored entries + */ + private boolean hasMenuEntries(MenuEntry[] menuEntries) + { + for (MenuEntry menuEntry : menuEntries) + { + switch (menuEntry.getMenuOpcode()) + { + case CANCEL: + case WALK: + break; + case EXAMINE_OBJECT: + case EXAMINE_NPC: + case EXAMINE_ITEM_GROUND: + case EXAMINE_ITEM: + case EXAMINE_ITEM_BANK_EQ: + if (cameraConfig.ignoreExamine()) + { + break; + } + default: + return true; + } + } + return false; + } + + /** + * Checks if the menu has any options, because menu entries are built each + * tick and the MouseListener runs on the awt thread + */ + @Subscribe + public void onClientTick(ClientTick event) + { + menuHasEntries = hasMenuEntries(client.getMenuEntries()); + } + + /** + * The event that is triggered when a mouse button is pressed + * In this method the right click is changed to a middle-click to enable rotating the camera + *

+ * This method also provides the config option to enable the middle-mouse button to always open the right click menu + */ + @Override + public MouseEvent mousePressed(MouseEvent mouseEvent) + { + if (SwingUtilities.isRightMouseButton(mouseEvent) && cameraConfig.rightClickMovesCamera()) + { + boolean oneButton = client.getVar(VarPlayer.MOUSE_BUTTONS) == 1; + // Only move the camera if there is nothing at the menu, or if + // in one-button mode. In one-button mode, left and right click always do the same thing, + // so always treat it as the menu is empty + if (!menuHasEntries || oneButton) + { + // Set the rightClick flag to true so we can release the button in mouseReleased() later + rightClick = true; + // Change the mousePressed() MouseEvent to the middle mouse button + mouseEvent = new MouseEvent((java.awt.Component) mouseEvent.getSource(), + mouseEvent.getID(), + mouseEvent.getWhen(), + mouseEvent.getModifiersEx(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger(), + MouseEvent.BUTTON2); + } + } + else if (SwingUtilities.isMiddleMouseButton((mouseEvent)) && cameraConfig.middleClickMenu()) + { + // Set the middleClick flag to true so we can release it later in mouseReleased() + middleClick = true; + // Chance the middle mouse button MouseEvent to a right-click + mouseEvent = new MouseEvent((java.awt.Component) mouseEvent.getSource(), + mouseEvent.getID(), + mouseEvent.getWhen(), + mouseEvent.getModifiersEx(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger(), + MouseEvent.BUTTON3); + } + return mouseEvent; + } + + /** + * Correct the MouseEvent to release the correct button + */ + @Override + public MouseEvent mouseReleased(MouseEvent mouseEvent) + { + if (rightClick) + { + rightClick = false; + // Change the MouseEvent to button 2 so the middle mouse button will be released + mouseEvent = new MouseEvent((java.awt.Component) mouseEvent.getSource(), + mouseEvent.getID(), + mouseEvent.getWhen(), + mouseEvent.getModifiersEx(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger(), + MouseEvent.BUTTON2); + + } + if (middleClick) + { + middleClick = false; + // Change the MouseEvent ot button 3 so the right mouse button will be released + mouseEvent = new MouseEvent((java.awt.Component) mouseEvent.getSource(), + mouseEvent.getID(), + mouseEvent.getWhen(), + mouseEvent.getModifiersEx(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger(), + MouseEvent.BUTTON3); + } + return mouseEvent; + } + + /* + * These methods are unused but required to be present in a MouseListener implementation + */ + // region Unused MouseListener methods + @Override + public MouseEvent mouseDragged(MouseEvent mouseEvent) + { + return mouseEvent; + } + + @Override + public MouseEvent mouseMoved(MouseEvent mouseEvent) + { + return mouseEvent; + } + + @Override + public MouseEvent mouseClicked(MouseEvent mouseEvent) + { + return mouseEvent; + } + + @Override + public MouseEvent mouseEntered(MouseEvent mouseEvent) + { + return mouseEvent; + } + + @Override + public MouseEvent mouseExited(MouseEvent mouseEvent) + { + return mouseEvent; + } + // endregion +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ControlFunction.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/ControlFunction.java similarity index 97% rename from runelite-client/src/main/java/net/runelite/client/plugins/zoom/ControlFunction.java rename to runelite-client/src/main/java/net/runelite/client/plugins/camera/ControlFunction.java index a6041ae6d6..c55a6269b1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ControlFunction.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/ControlFunction.java @@ -23,7 +23,7 @@ * 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.zoom; +package net.runelite.client.plugins.camera; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java index a7e4963bcc..1e7d7b7cd7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java @@ -24,9 +24,12 @@ */ package net.runelite.client.plugins.chatcommands; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Keybind; @ConfigGroup("chatcommands") public interface ChatCommandsConfig extends Config @@ -121,17 +124,28 @@ public interface ChatCommandsConfig extends Config @ConfigItem( position = 8, - keyName = "clearShortcuts", - name = "Clear shortcuts", - description = "Enable shortcuts (ctrl+w and backspace) for clearing the chatbox" + keyName = "clearSingleWord", + name = "Clear Single Word", + description = "Enable hot key to clear single word at a time" ) - default boolean clearShortcuts() + default Keybind clearSingleWord() { - return true; + return new Keybind(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK); } @ConfigItem( - position = 5, + position = 9, + keyName = "clearEntireChatBox", + name = "Clear Chat Box", + description = "Enable hotkey to clear entire chat box" + ) + default Keybind clearChatBox() + { + return new Keybind(KeyEvent.VK_BACK_SPACE, InputEvent.CTRL_DOWN_MASK); + } + + @ConfigItem( + position = 10, keyName = "clipboardShortcuts", name = "Clipboard shortcuts", description = "Enable clipboard shortcuts (ctrl+c and ctrl+v)" diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatKeyboardListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatKeyboardListener.java index a4b269f912..553724596b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatKeyboardListener.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatKeyboardListener.java @@ -28,12 +28,10 @@ import java.awt.event.KeyEvent; import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.Client; -import net.runelite.api.GameState; import net.runelite.api.ScriptID; import net.runelite.api.VarClientStr; import net.runelite.client.callback.ClientThread; import net.runelite.client.input.KeyListener; -import net.runelite.client.util.Clipboard; @Singleton class ChatKeyboardListener implements KeyListener @@ -56,85 +54,43 @@ class ChatKeyboardListener implements KeyListener @Override public void keyPressed(KeyEvent e) { - if (!e.isControlDown() || client.getGameState() != GameState.LOGGED_IN) + if (chatCommandsConfig.clearSingleWord().matches(e)) { - return; - } - - String input = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT); - - switch (e.getKeyCode()) - { - case KeyEvent.VK_C: - if (!chatCommandsConfig.clipboardShortcuts()) + String input = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT); + if (input != null) + { + // remove trailing space + while (input.endsWith(" ")) { - break; + input = input.substring(0, input.length() - 1); } - Clipboard.store(input); - - break; - case KeyEvent.VK_V: - if (!chatCommandsConfig.clipboardShortcuts()) + // find next word + int idx = input.lastIndexOf(' '); + final String replacement; + if (idx != -1) { - break; + replacement = input.substring(0, idx); + } + else + { + replacement = ""; } - final String clipboard = Clipboard.retrieve(); - if (clipboard != null && !clipboard.isEmpty()) - { - final String replacement = input + clipboard; - - clientThread.invoke(() -> client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, replacement)); - } - - break; - case KeyEvent.VK_W: - if (!chatCommandsConfig.clearShortcuts()) - { - break; - } - - if (input != null) - { - // remove trailing space - while (input.endsWith(" ")) - { - input = input.substring(0, input.length() - 1); - } - - // find next word - int idx = input.lastIndexOf(' '); - final String replacement; - if (idx != -1) - { - replacement = input.substring(0, idx); - } - else - { - replacement = ""; - } - - clientThread.invoke(() -> - { - client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, replacement); - client.runScript(ScriptID.CHAT_PROMPT_INIT); - }); - } - break; - case KeyEvent.VK_BACK_SPACE: clientThread.invoke(() -> { - client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, ""); + client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, replacement); client.runScript(ScriptID.CHAT_PROMPT_INIT); }); - if (!chatCommandsConfig.clearShortcuts()) - { - break; - } - - clientThread.invoke(() -> client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, "")); - break; + } + } + else if (chatCommandsConfig.clearChatBox().matches(e)) + { + clientThread.invoke(() -> + { + client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, ""); + client.runScript(ScriptID.CHAT_PROMPT_INIT); + }); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/leaguechaticons/LeagueChatIconsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/leaguechaticons/LeagueChatIconsPlugin.java index 09619f86ad..d4bcfcba6a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/leaguechaticons/LeagueChatIconsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/leaguechaticons/LeagueChatIconsPlugin.java @@ -54,7 +54,7 @@ import net.runelite.http.api.worlds.WorldResult; import net.runelite.http.api.worlds.WorldType; @PluginDescriptor( - name = "Chat League Icons", + name = "League Chat Icons", description = "Changes the chat icon for players on league worlds", enabledByDefault = false ) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java index 1f5df989b3..517e7f7349 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java @@ -328,7 +328,7 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener return; } - markObject(name, object); + markObject(objectDefinition, name, object); } private void checkObjectPoints(TileObject object) @@ -350,7 +350,8 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener for (ObjectPoint objectPoint : objectPoints) { if (worldPoint.getRegionX() == objectPoint.getRegionX() - && worldPoint.getRegionY() == objectPoint.getRegionY()) + && worldPoint.getRegionY() == objectPoint.getRegionY() + && object.getPlane() == objectPoint.getZ()) { // Transform object to get the name which matches against what we've stored ObjectDefinition objectDefinition = getObjectDefinition(object.getId()); @@ -432,13 +433,14 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener return false; } - private void markObject(String name, final TileObject object) + /** mark or unmark an object + * + * @param objectComposition transformed composition of object based on vars + * @param name name of objectComposition + * @param object tile object, for multilocs object.getId() is the base id + */ + private void markObject(ObjectDefinition objectComposition, String name, final TileObject object) { - if (object == null) - { - return; - } - final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation()); if (worldPoint == null) { @@ -457,9 +459,11 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener if (objects.remove(object)) { - // Use object id instead of name to match the object point with this object due to the object name being - // able to change because of multilocs. - if (!objectPoints.removeIf(op -> (op.getId() == -1 || op.getId() == object.getId()) + // Find the object point that caused this object to be marked, there are two cases: + // 1) object is a multiloc, the name may have changed since marking - match from base id + // 2) not a multiloc, but an object has spawned with an identical name and a different + // id as what was originally marked + if (!objectPoints.removeIf(op -> ((op.getId() == -1 || op.getId() == object.getId()) || op.getName().equals(objectComposition.getName())) && op.getRegionX() == worldPoint.getRegionX() && op.getRegionY() == worldPoint.getRegionY() && op.getZ() == worldPoint.getPlane())) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomPlugin.java deleted file mode 100644 index 10990c7842..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomPlugin.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2018 Abex - * Copyright (c) 2018, 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.zoom; - -import com.google.inject.Inject; -import com.google.inject.Provides; -import java.awt.event.KeyEvent; -import net.runelite.api.Client; -import net.runelite.api.ScriptID; -import net.runelite.api.events.FocusChanged; -import net.runelite.api.events.ScriptCallbackEvent; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.events.ConfigChanged; -import net.runelite.client.input.KeyListener; -import net.runelite.client.input.KeyManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.util.MiscUtils; - -@PluginDescriptor( - name = "Camera Zoom", - description = "Expand zoom limit and/or enable vertical camera", - tags = {"limit", "vertical"}, - enabledByDefault = false -) -public class ZoomPlugin extends Plugin implements KeyListener -{ - /** - * The largest (most zoomed in) value that can be used without the client crashing. - *

- * Larger values trigger an overflow in the engine's fov to scale code. - */ - private static final int INNER_ZOOM_LIMIT = 1004; - private static final int DEFAULT_ZOOM_INCREMENT = 25; - - private boolean controlDown; - - @Inject - private Client client; - - @Inject - private ClientThread clientThread; - - @Inject - private ZoomConfig zoomConfig; - - @Inject - private KeyManager keyManager; - - @Provides - ZoomConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(ZoomConfig.class); - } - - @Subscribe - private void onScriptCallbackEvent(ScriptCallbackEvent event) - { - if (client.getIndexScripts().isOverlayOutdated()) - { - // if any cache overlay fails to load then assume at least one of the zoom scripts is outdated - // and prevent zoom extending entirely. - return; - } - - int[] intStack = client.getIntStack(); - int intStackSize = client.getIntStackSize(); - - if (!controlDown && "scrollWheelZoom".equals(event.getEventName()) && zoomConfig.controlFunction() == ControlFunction.CONTROL_TO_ZOOM) - { - intStack[intStackSize - 1] = 1; - } - - if ("innerZoomLimit".equals(event.getEventName()) && zoomConfig.innerLimit()) - { - intStack[intStackSize - 1] = INNER_ZOOM_LIMIT; - return; - } - - if ("outerZoomLimit".equals(event.getEventName())) - { - int outerLimit = MiscUtils.clamp(zoomConfig.outerLimit(), ZoomConfig.OUTER_LIMIT_MIN, ZoomConfig.OUTER_LIMIT_MAX); - int outerZoomLimit = 128 - outerLimit; - intStack[intStackSize - 1] = outerZoomLimit; - return; - } - - if ("scrollWheelZoomIncrement".equals(event.getEventName()) && zoomConfig.zoomIncrement() != DEFAULT_ZOOM_INCREMENT) - { - intStack[intStackSize - 1] = zoomConfig.zoomIncrement(); - return; - } - - if (zoomConfig.innerLimit()) - { - // This lets the options panel's slider have an exponential rate - final double exponent = 2.d; - switch (event.getEventName()) - { - case "zoomLinToExp": - { - double range = intStack[intStackSize - 1]; - double value = intStack[intStackSize - 2]; - value = Math.pow(value / range, exponent) * range; - intStack[intStackSize - 2] = (int) value; - break; - } - case "zoomExpToLin": - { - double range = intStack[intStackSize - 1]; - double value = intStack[intStackSize - 2]; - value = Math.pow(value / range, 1.d / exponent) * range; - intStack[intStackSize - 2] = (int) value; - break; - } - } - } - } - - @Subscribe - private void onFocusChanged(FocusChanged event) - { - if (!event.isFocused()) - { - controlDown = false; - } - } - - @Override - protected void startUp() - { - - client.setCameraPitchRelaxerEnabled(zoomConfig.relaxCameraPitch()); - keyManager.registerKeyListener(this); - } - - @Override - protected void shutDown() - { - client.setCameraPitchRelaxerEnabled(false); - keyManager.unregisterKeyListener(this); - controlDown = false; - } - - @Subscribe - private void onConfigChanged(ConfigChanged ev) - { - client.setCameraPitchRelaxerEnabled(zoomConfig.relaxCameraPitch()); - } - - @Override - public void keyTyped(KeyEvent e) - { - } - - @Override - public void keyPressed(KeyEvent e) - { - if (e.getKeyCode() == KeyEvent.VK_CONTROL) - { - controlDown = true; - } - } - - @Override - public void keyReleased(KeyEvent e) - { - if (e.getKeyCode() == KeyEvent.VK_CONTROL) - { - controlDown = false; - - if (zoomConfig.controlFunction() == ControlFunction.CONTROL_TO_RESET) - { - final int zoomValue = MiscUtils.clamp(zoomConfig.ctrlZoomValue(), zoomConfig.OUTER_LIMIT_MIN, INNER_ZOOM_LIMIT); - clientThread.invokeLater(() -> client.runScript(ScriptID.CAMERA_DO_ZOOM, zoomValue, zoomValue)); - } - } - } -} \ No newline at end of file diff --git a/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java b/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java index 15081fe93a..bfacb59016 100644 --- a/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java +++ b/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Adam + * Copyright (c) 2016-2019, Adam * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,32 +22,49 @@ * (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.rs; +import com.google.common.base.Charsets; +import com.google.common.io.CharStreams; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.After; +import static org.junit.Assert.assertEquals; +import org.junit.Before; import org.junit.Test; -/** - * @author Adam - */ public class ClientConfigLoaderTest { - @Test - public void test() + private final MockWebServer server = new MockWebServer(); + + @Before + public void before() throws IOException { - final RSConfig config = ClientConfigLoader.fetch().blockingGet(); - - for (String key : config.getClassLoaderProperties().keySet()) + String response; + try (InputStream in = getClass().getResourceAsStream("jav_config.ws")) { - System.out.println(key + ": " + config.getClassLoaderProperties().get(key)); + response = CharStreams.toString(new InputStreamReader( + in, Charsets.UTF_8)); } + server.enqueue(new MockResponse().setBody(response)); - System.out.println("Applet properties:"); - - for (String key : config.getAppletProperties().keySet()) - { - System.out.println(key + ": " + config.getAppletProperties().get(key)); - } + server.start(); } -} + @After + public void after() throws IOException + { + server.shutdown(); + } + + @Test + public void testFetch() throws IOException + { + final RSConfig config = ClientConfigLoader.fetch(server.url("/")); + assertEquals("http://oldschool1.runescape.com/", config.getCodeBase()); + } + +} \ No newline at end of file diff --git a/runelite-client/src/test/resources/net/runelite/client/rs/jav_config.ws b/runelite-client/src/test/resources/net/runelite/client/rs/jav_config.ws new file mode 100644 index 0000000000..f3ab2531fb --- /dev/null +++ b/runelite-client/src/test/resources/net/runelite/client/rs/jav_config.ws @@ -0,0 +1,65 @@ +title=Old School RuneScape +adverturl=http://www.runescape.com/g=oldscape/bare_advert.ws +codebase=http://oldschool1.runescape.com/ +cachedir=oldschool +storebase=0 +initial_jar=gamepack_6140455.jar +initial_class=client.class +termsurl=http://www.jagex.com/g=oldscape/terms/terms.ws +privacyurl=http://www.jagex.com/g=oldscape/privacy/privacy.ws +viewerversion=124 +win_sub_version=1 +mac_sub_version=2 +other_sub_version=2 +browsercontrol_win_x86_jar=browsercontrol_0_-1928975093.jar +browsercontrol_win_amd64_jar=browsercontrol_1_1674545273.jar +download=1276414 +window_preferredwidth=800 +window_preferredheight=600 +advert_height=96 +applet_minwidth=765 +applet_minheight=503 +applet_maxwidth=5760 +applet_maxheight=2160 +msg=lang0=English +msg=tandc=This game is copyright © 1999 - 2019 Jagex Ltd.\Use of this game is subject to our ["http://www.runescape.com/terms/terms.ws"Terms and Conditions] and ["http://www.runescape.com/privacy/privacy.ws"Privacy Policy]. +msg=options=Options +msg=language=Language +msg=changes_on_restart=Your changes will take effect when you next start this program. +msg=loading_app_resources=Loading application resources +msg=err_verify_bc64=Unable to verify browsercontrol64 +msg=err_verify_bc=Unable to verify browsercontrol +msg=err_load_bc=Unable to load browsercontrol +msg=loading_app=Loading application +msg=err_create_target=Unable to create target applet +msg=err_create_advertising=Unable to create advertising +msg=err_save_file=Error saving file +msg=err_downloading=Error downloading +msg=ok=OK +msg=cancel=Cancel +msg=message=Message +msg=copy_paste_url=Please copy and paste the following URL into your web browser +msg=information=Information +msg=err_get_file=Error getting file +msg=new_version=Update available! You can now launch the client directly from the OldSchool website.\nGet the new version from the link on the OldSchool homepage: http://oldschool.runescape.com/ +msg=new_version_linktext=Open OldSchool Homepage +msg=new_version_link=http://oldschool.runescape.com/ +param=14=0 +param=12=301 +param=11=https://auth.jagex.com/ +param=13=.runescape.com +param=3=false +param=6=0 +param=7=0 +param=9=ElZAIrq5NpKN6D3mDdihco3oPeYN2KFy2DCquj7JMmECPmLrDP3Bnw +param=15=0 +param=10=5 +param=8=true +param=17=http://www.runescape.com/g=oldscape/slr.ws?order=LPWM +param=2=https://payments.jagex.com/operator/v1/ +param=18= +param=4=45569 +param=1=1 +param=19=196515767263-1oo20deqm6edn7ujlihl6rpadk9drhva.apps.googleusercontent.com +param=16=false +param=5=0 \ No newline at end of file