This commit is contained in:
therealunull
2020-12-14 09:16:20 -05:00
parent 695e331d22
commit ce8c0cbb64
4 changed files with 763 additions and 0 deletions

View File

@@ -2081,9 +2081,15 @@ public interface Client extends GameShell
List<String> getOutdatedScripts();
//TODO: Implement
void queueChangedVarp(int varp);
//TODO: Implement
VarbitComposition getVarbit(Integer id);
//TODO: Implement
Widget getWidget(int param1);
//TODO: Implement
Widget getScriptActiveWidget();
}

View File

@@ -0,0 +1,183 @@
/*
* 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.camera;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Range;
@ConfigGroup("zoom") // using the old plugin's group name
public interface CameraConfig extends Config
{
int OUTER_LIMIT_MIN = -400;
int OUTER_LIMIT_MAX = 400;
/**
* 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.
*/
int INNER_ZOOM_LIMIT = 1004;
@ConfigItem(
keyName = "inner",
name = "Expand inner zoom limit",
description = "Configures whether or not the inner zoom limit is reduced",
position = 1
)
default boolean innerLimit()
{
return false;
}
@Range(
min = OUTER_LIMIT_MIN,
max = OUTER_LIMIT_MAX
)
@ConfigItem(
keyName = "outerLimit",
name = "Expand outer zoom limit",
description = "Configures how much the outer zoom limit is adjusted",
position = 2
)
default int outerLimit()
{
return 0;
}
@ConfigItem(
keyName = "relaxCameraPitch",
name = "Vertical camera",
description = "Relax the camera's upper pitch limit",
position = 3
)
default boolean relaxCameraPitch()
{
return false;
}
@ConfigItem(
keyName = "controlFunction",
name = "Control Function",
description = "Configures the zoom function when control is pressed",
position = 4
)
default ControlFunction controlFunction()
{
return ControlFunction.NONE;
}
@ConfigItem(
keyName = "ctrlZoomValue",
name = "Reset zoom position",
description = "Position of zoom when it is reset",
position = 5
)
@Range(
min = OUTER_LIMIT_MIN,
max = INNER_ZOOM_LIMIT
)
default int ctrlZoomValue()
{
return 512;
}
@ConfigItem(
keyName = "zoomIncrement",
name = "Zoom Speed",
description = "Speed of zoom",
position = 6
)
default int zoomIncrement()
{
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;
}
@ConfigItem(
keyName = "compassLook",
name = "Compass options",
description = "Adds Look South, East, and West options to the compass",
position = 10
)
default boolean compassLook()
{
return true;
}
@ConfigItem(
keyName = "invertYaw",
name = "Invert Yaw",
description = "Makes moving the camera horizontally with the mouse backwards",
position = 11
)
default boolean invertYaw()
{
return false;
}
@ConfigItem(
keyName = "invertPitch",
name = "Invert Pitch",
description = "Makes moving the camera vertically with the mouse backwards",
position = 12
)
default boolean invertPitch()
{
return false;
}
}

View File

@@ -0,0 +1,528 @@
/*
* Copyright (c) 2018 Abex
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* Copyright (c) 2019, Wynadorn <https://github.com/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.common.primitives.Ints;
import com.google.inject.Provides;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import javax.inject.Inject;
import javax.swing.SwingUtilities;
import net.runelite.api.Client;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.ScriptID;
import net.runelite.api.SettingID;
import net.runelite.api.VarClientInt;
import net.runelite.api.VarPlayer;
import net.runelite.api.events.BeforeRender;
import net.runelite.api.events.ClientTick;
import net.runelite.api.events.FocusChanged;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.events.ScriptPreFired;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
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.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
@PluginDescriptor(
name = "Camera",
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
{
private static final int DEFAULT_ZOOM_INCREMENT = 25;
private static final int DEFAULT_OUTER_ZOOM_LIMIT = 128;
static final int DEFAULT_INNER_ZOOM_LIMIT = 896;
private static final String LOOK_NORTH = "Look North";
private static final String LOOK_SOUTH = "Look South";
private static final String LOOK_EAST = "Look East";
private static final String LOOK_WEST = "Look West";
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 config;
@Inject
private KeyManager keyManager;
@Inject
private MouseManager mouseManager;
@Inject
private TooltipManager tooltipManager;
private Tooltip sliderTooltip;
@Provides
CameraConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(CameraConfig.class);
}
@Override
protected void startUp()
{
rightClick = false;
middleClick = false;
menuHasEntries = false;
copyConfigs();
keyManager.registerKeyListener(this);
mouseManager.registerMouseListener(this);
clientThread.invoke(() ->
{
Widget sideSlider = client.getWidget(WidgetInfo.SETTINGS_SIDE_CAMERA_ZOOM_SLIDER_TRACK);
if (sideSlider != null)
{
addZoomTooltip(sideSlider);
}
Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT);
if (settingsInit != null)
{
throw new UnsupportedOperationException("Implement");
//client.createScriptEvent(settingsInit.getOnLoadListener())
//.setSource(settingsInit)
//.run();
}
});
}
@Override
protected void shutDown()
{
client.setCameraPitchRelaxerEnabled(false);
client.setInvertYaw(false);
client.setInvertPitch(false);
keyManager.unregisterKeyListener(this);
mouseManager.unregisterMouseListener(this);
controlDown = false;
clientThread.invoke(() ->
{
Widget sideSlider = client.getWidget(WidgetInfo.SETTINGS_SIDE_CAMERA_ZOOM_SLIDER_TRACK);
if (sideSlider != null)
{
sideSlider.setOnMouseRepeatListener((Object[]) null);
}
Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT);
if (settingsInit != null)
{
throw new UnsupportedOperationException("Implement");
//client.createScriptEvent(settingsInit.getOnLoadListener())
//.setSource(settingsInit)
//.run();
}
});
}
void copyConfigs()
{
client.setCameraPitchRelaxerEnabled(config.relaxCameraPitch());
client.setInvertYaw(config.invertYaw());
client.setInvertPitch(config.invertPitch());
}
@Subscribe
public void onMenuEntryAdded(MenuEntryAdded menuEntryAdded)
{
if (menuEntryAdded.getType() == MenuAction.CC_OP.getId() && menuEntryAdded.getOption().equals(LOOK_NORTH) && config.compassLook())
{
MenuEntry[] menuEntries = client.getMenuEntries();
int len = menuEntries.length;
MenuEntry north = menuEntries[len - 1];
menuEntries = Arrays.copyOf(menuEntries, len + 3);
// The handling for these entries is done in ToplevelCompassOp.rs2asm
menuEntries[--len] = createCameraLookEntry(menuEntryAdded, 4, LOOK_WEST);
menuEntries[++len] = createCameraLookEntry(menuEntryAdded, 3, LOOK_EAST);
menuEntries[++len] = createCameraLookEntry(menuEntryAdded, 2, LOOK_SOUTH);
menuEntries[++len] = north;
client.setMenuEntries(menuEntries);
}
}
private MenuEntry createCameraLookEntry(MenuEntryAdded lookNorth, int identifier, String option)
{
MenuEntry m = new MenuEntry();
m.setOption(option);
m.setTarget(lookNorth.getTarget());
m.setIdentifier(identifier);
m.setType(MenuAction.CC_OP.getId());
m.setParam0(lookNorth.getActionParam0());
m.setParam1(lookNorth.getActionParam1());
return m;
}
@Subscribe
public 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()) && config.controlFunction() == ControlFunction.CONTROL_TO_ZOOM)
{
intStack[intStackSize - 1] = 1;
}
if ("innerZoomLimit".equals(event.getEventName()) && config.innerLimit())
{
intStack[intStackSize - 1] = CameraConfig.INNER_ZOOM_LIMIT;
return;
}
if ("outerZoomLimit".equals(event.getEventName()))
{
int outerLimit = Ints.constrainToRange(config.outerLimit(), CameraConfig.OUTER_LIMIT_MIN, CameraConfig.OUTER_LIMIT_MAX);
int outerZoomLimit = DEFAULT_OUTER_ZOOM_LIMIT - outerLimit;
intStack[intStackSize - 1] = outerZoomLimit;
return;
}
if ("scrollWheelZoomIncrement".equals(event.getEventName()) && config.zoomIncrement() != DEFAULT_ZOOM_INCREMENT)
{
intStack[intStackSize - 1] = config.zoomIncrement();
return;
}
if (config.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
public void onFocusChanged(FocusChanged event)
{
if (!event.isFocused())
{
controlDown = false;
}
}
@Subscribe
public void onConfigChanged(ConfigChanged ev)
{
copyConfigs();
}
@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 (config.controlFunction() == ControlFunction.CONTROL_TO_RESET)
{
final int zoomValue = Ints.constrainToRange(config.ctrlZoomValue(), CameraConfig.OUTER_LIMIT_MIN, CameraConfig.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)
{
MenuAction action = MenuAction.of(menuEntry.getType());
switch (action)
{
case CANCEL:
case WALK:
break;
case EXAMINE_OBJECT:
case EXAMINE_NPC:
case EXAMINE_ITEM_GROUND:
case EXAMINE_ITEM:
case CC_OP_LOW_PRIORITY:
if (config.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());
}
@Subscribe
private void onScriptPreFired(ScriptPreFired ev)
{
if (ev.getScriptId() == ScriptID.SETTINGS_SLIDER_CHOOSE_ONOP)
{
int arg = client.getIntStackSize() - 7;
int[] is = client.getIntStack();
if (is[arg] == SettingID.CAMERA_ZOOM)
{
addZoomTooltip(client.getScriptActiveWidget());
}
}
}
@Subscribe
private void onWidgetLoaded(WidgetLoaded ev)
{
if (ev.getGroupId() == WidgetID.SETTINGS_SIDE_GROUP_ID)
{
addZoomTooltip(client.getWidget(WidgetInfo.SETTINGS_SIDE_CAMERA_ZOOM_SLIDER_TRACK));
}
}
private void addZoomTooltip(Widget w)
{
w.setOnMouseRepeatListener((JavaScriptCallback) ev ->
{
int value = client.getVar(VarClientInt.CAMERA_ZOOM_RESIZABLE_VIEWPORT);
int max = config.innerLimit() ? config.INNER_ZOOM_LIMIT : CameraPlugin.DEFAULT_INNER_ZOOM_LIMIT;
sliderTooltip = new Tooltip("Camera Zoom: " + value + " / " + max);
});
}
@Subscribe
private void onBeforeRender(BeforeRender ev)
{
if (sliderTooltip != null)
{
tooltipManager.add(sliderTooltip);
sliderTooltip = null;
}
}
/**
* 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
* <p>
* 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) && config.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)) && config.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
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2019, Jacob M <https://github.com/jacoblairm>
* 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 HOLDER 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 lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ControlFunction
{
NONE("None"),
CONTROL_TO_ZOOM("Hold to zoom"),
CONTROL_TO_RESET("Reset zoom");
private final String name;
@Override
public String toString()
{
return getName();
}
}