project: Update mixins

This commit is contained in:
Owain van Brakel
2019-11-06 12:38:16 +01:00
parent 5efce1e3d6
commit ce8f3f48c0
23 changed files with 814 additions and 322 deletions

View File

@@ -247,6 +247,11 @@ public class MenuManager
private void onMenuEntryAdded(MenuEntryAdded event)
{
if (client.isSpellSelected())
{
return;
}
for (AbstractComparableEntry e : hiddenEntries)
{
if (e.matches(event))

View File

@@ -37,8 +37,6 @@ import java.awt.geom.Rectangle2D;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.Constants;
@@ -76,9 +74,6 @@ import net.runelite.client.ui.overlay.tooltip.TooltipManager;
@Singleton
class DevToolsOverlay extends Overlay
{
private static final int ITEM_EMPTY = 6512;
private static final int ITEM_FILLED = 20594;
private static final Font FONT = FontManager.getRunescapeFont().deriveFont(Font.BOLD, 16);
private static final Color RED = new Color(221, 44, 0);
private static final Color GREEN = new Color(0, 200, 83);
@@ -97,13 +92,6 @@ class DevToolsOverlay extends Overlay
private final DevToolsPlugin plugin;
private final TooltipManager toolTipManager;
@Setter
@Getter
private Widget widget;
@Setter
private int itemIndex = -1;
@Inject
private DevToolsOverlay(Client client, DevToolsPlugin plugin, TooltipManager toolTipManager)
{
@@ -155,8 +143,6 @@ class DevToolsOverlay extends Overlay
renderCursorTooltip(graphics);
}
renderWidgets(graphics);
return null;
}
@@ -490,70 +476,6 @@ class DevToolsOverlay extends Overlay
}
}
private void renderWidgets(Graphics2D graphics)
{
if (widget == null || widget.isHidden())
{
return;
}
Rectangle childBounds = widget.getBounds();
graphics.setColor(CYAN);
graphics.draw(childBounds);
if (itemIndex == -1)
{
return;
}
if (widget.getItemId() != ITEM_EMPTY
&& widget.getItemId() != ITEM_FILLED)
{
Rectangle componentBounds = widget.getBounds();
graphics.setColor(ORANGE);
graphics.draw(componentBounds);
renderWidgetText(graphics, componentBounds, widget.getItemId(), YELLOW);
}
WidgetItem widgetItem = widget.getWidgetItem(itemIndex);
if (widgetItem == null
|| widgetItem.getId() < 0
|| widgetItem.getId() == ITEM_EMPTY
|| widgetItem.getId() == ITEM_FILLED)
{
return;
}
Rectangle itemBounds = widgetItem.getCanvasBounds();
graphics.setColor(ORANGE);
graphics.draw(itemBounds);
renderWidgetText(graphics, itemBounds, widgetItem.getId(), YELLOW);
}
private void renderWidgetText(Graphics2D graphics, Rectangle bounds, int itemId, Color color)
{
if (itemId == -1)
{
return;
}
String text = itemId + "";
FontMetrics fm = graphics.getFontMetrics();
Rectangle2D textBounds = fm.getStringBounds(text, graphics);
int textX = (int) (bounds.getX() + (bounds.getWidth() / 2) - (textBounds.getWidth() / 2));
int textY = (int) (bounds.getY() + (bounds.getHeight() / 2) + (textBounds.getHeight() / 2));
graphics.setColor(Color.BLACK);
graphics.drawString(text, textX + 1, textY + 1);
graphics.setColor(color);
graphics.drawString(text, textX, textY);
}
private void renderPlayerWireframe(Graphics2D graphics, Player player, Color color)
{
Polygon[] polys = player.getPolygons();

View File

@@ -27,13 +27,20 @@
package net.runelite.client.plugins.devtools;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Collection;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.stream.Stream;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
@@ -45,29 +52,67 @@ import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.MenuEntry;
import net.runelite.api.MenuOpcode;
import net.runelite.api.SpriteID;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.ColorUtil;
@Slf4j
@Singleton
class WidgetInspector extends JFrame
{
private static final Map<Integer, WidgetInfo> widgetIdMap = new HashMap<>();
static final Color SELECTED_WIDGET_COLOR = Color.CYAN;
private static final float SELECTED_WIDGET_HUE;
static
{
float[] hsb = new float[3];
Color.RGBtoHSB(SELECTED_WIDGET_COLOR.getRed(), SELECTED_WIDGET_COLOR.getGreen(), SELECTED_WIDGET_COLOR.getBlue(), hsb);
SELECTED_WIDGET_HUE = hsb[0];
}
private final Client client;
private final ClientThread clientThread;
private final DevToolsConfig config;
private final DevToolsOverlay overlay;
private final Provider<WidgetInspectorOverlay> overlay;
private final OverlayManager overlayManager;
private final JTree widgetTree;
private final WidgetInfoTableModel infoTableModel;
private final JCheckBox alwaysOnTop;
private final JCheckBox hideHidden;
private static final Map<Integer, WidgetInfo> widgetIdMap = new HashMap<>();
private DefaultMutableTreeNode root;
@Getter
private Widget selectedWidget;
@Getter
private int selectedItem;
private Widget picker = null;
@Getter
private boolean pickerSelected = false;
@Inject
private WidgetInspector(
@@ -75,17 +120,21 @@ class WidgetInspector extends JFrame
ClientThread clientThread,
WidgetInfoTableModel infoTableModel,
DevToolsConfig config,
DevToolsPlugin plugin,
EventBus eventBus,
DevToolsOverlay overlay,
DevToolsPlugin plugin)
Provider<WidgetInspectorOverlay> overlay,
OverlayManager overlayManager)
{
this.client = client;
this.clientThread = clientThread;
this.infoTableModel = infoTableModel;
this.config = config;
this.overlay = overlay;
this.overlayManager = overlayManager;
eventBus.subscribe(ConfigChanged.class, this, this::onConfigChanged);
eventBus.subscribe(MenuOptionClicked.class, this, this::onMenuOptionClicked);
eventBus.subscribe(MenuEntryAdded.class, this, this::onMenuEntryAdded);
setTitle("RuneLite Widget Inspector");
setIconImage(ClientUI.ICON);
@@ -96,7 +145,6 @@ class WidgetInspector extends JFrame
@Override
public void windowClosing(WindowEvent e)
{
eventBus.unregister(this);
close();
plugin.getWidgetInspector().setActive(false);
}
@@ -114,16 +162,12 @@ class WidgetInspector extends JFrame
{
WidgetTreeNode node = (WidgetTreeNode) selected;
Widget widget = node.getWidget();
overlay.setWidget(widget);
overlay.setItemIndex(widget.getItemId());
refreshInfo();
log.debug("Set widget to {} and item index to {}", widget, widget.getItemId());
setSelectedWidget(widget, -1, false);
}
else if (selected instanceof WidgetItemNode)
{
WidgetItemNode node = (WidgetItemNode) selected;
overlay.setItemIndex(node.getWidgetItem().getIndex());
log.debug("Set item index to {}", node.getWidgetItem().getIndex());
setSelectedWidget(node.getWidgetItem().getWidget(), node.getWidgetItem().getIndex(), false);
}
});
@@ -149,15 +193,20 @@ class WidgetInspector extends JFrame
onConfigChanged(null);
bottomPanel.add(alwaysOnTop);
hideHidden = new JCheckBox("Hide hidden");
hideHidden.setSelected(true);
hideHidden.addItemListener(ev -> refreshWidgets());
bottomPanel.add(hideHidden);
final JButton revalidateWidget = new JButton("Revalidate");
revalidateWidget.addActionListener(ev -> clientThread.invokeLater(() ->
{
if (overlay.getWidget() == null)
if (selectedWidget == null)
{
return;
}
overlay.getWidget().revalidate();
selectedWidget.revalidate();
}));
bottomPanel.add(revalidateWidget);
@@ -165,7 +214,6 @@ class WidgetInspector extends JFrame
add(split, BorderLayout.CENTER);
pack();
}
private void onConfigChanged(ConfigChanged ev)
@@ -180,10 +228,13 @@ class WidgetInspector extends JFrame
clientThread.invokeLater(() ->
{
Widget[] rootWidgets = client.getWidgetRoots();
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
root = new DefaultMutableTreeNode();
overlay.setWidget(null);
overlay.setItemIndex(-1);
Widget wasSelectedWidget = selectedWidget;
int wasSelectedItem = selectedItem;
selectedWidget = null;
selectedItem = -1;
for (Widget widget : rootWidgets)
{
@@ -196,17 +247,15 @@ class WidgetInspector extends JFrame
SwingUtilities.invokeLater(() ->
{
overlay.setWidget(null);
overlay.setItemIndex(-1);
refreshInfo();
widgetTree.setModel(new DefaultTreeModel(root));
setSelectedWidget(wasSelectedWidget, wasSelectedItem, true);
});
});
}
private DefaultMutableTreeNode addWidget(String type, Widget widget)
{
if (widget == null || widget.isHidden())
if (widget == null || (hideHidden.isSelected() && widget.isHidden()))
{
return null;
}
@@ -269,9 +318,70 @@ class WidgetInspector extends JFrame
return node;
}
private void refreshInfo()
private void setSelectedWidget(Widget widget, int item, boolean updateTree)
{
infoTableModel.setWidget(overlay.getWidget());
infoTableModel.setWidget(widget);
if (this.selectedWidget == widget && this.selectedItem == item)
{
return;
}
this.selectedWidget = widget;
this.selectedItem = item;
if (root == null || !updateTree)
{
return;
}
clientThread.invoke(() ->
{
Stack<Widget> treePath = new Stack<>();
for (Widget w = widget; w != null; w = w.getParent())
{
treePath.push(w);
}
DefaultMutableTreeNode node = root;
deeper:
for (; !treePath.empty(); )
{
Widget w = treePath.pop();
for (Enumeration<?> it = node.children(); it.hasMoreElements(); )
{
WidgetTreeNode inner = (WidgetTreeNode) it.nextElement();
if (inner.getWidget().getId() == w.getId() && inner.getWidget().getIndex() == w.getIndex())
{
node = inner;
continue deeper;
}
}
}
if (selectedItem != -1)
{
for (Enumeration<?> it = node.children(); it.hasMoreElements(); )
{
Object wiw = it.nextElement();
if (wiw instanceof WidgetItemNode)
{
WidgetItemNode inner = (WidgetItemNode) wiw;
if (inner.getWidgetItem().getIndex() == selectedItem)
{
node = inner;
break;
}
}
}
}
final DefaultMutableTreeNode fnode = node;
SwingUtilities.invokeLater(() ->
{
widgetTree.getSelectionModel().clearSelection();
widgetTree.getSelectionModel().addSelectionPath(new TreePath(fnode.getPath()));
});
});
}
static WidgetInfo getWidgetInfo(int packedId)
@@ -295,12 +405,176 @@ class WidgetInspector extends JFrame
setVisible(true);
toFront();
repaint();
overlayManager.add(this.overlay.get());
clientThread.invokeLater(this::addPickerWidget);
}
public void close()
{
overlay.setWidget(null);
overlay.setItemIndex(-1);
overlayManager.remove(this.overlay.get());
clientThread.invokeLater(this::removePickerWidget);
setSelectedWidget(null, -1, false);
setVisible(false);
}
}
private void removePickerWidget()
{
if (picker == null)
{
return;
}
Widget parent = picker.getParent();
if (parent == null)
{
return;
}
Widget[] children = parent.getChildren();
if (children == null || children.length <= picker.getIndex() || children[picker.getIndex()] != picker)
{
return;
}
children[picker.getIndex()] = null;
}
private void addPickerWidget()
{
removePickerWidget();
int x = 10, y = 2;
Widget parent = client.getWidget(WidgetInfo.MINIMAP_ORBS);
if (parent == null)
{
Widget[] roots = client.getWidgetRoots();
parent = Stream.of(roots)
.filter(w -> w.getType() == WidgetType.LAYER && w.getContentType() == 0 && !w.isSelfHidden())
.sorted(Comparator.comparing((Widget w) -> w.getRelativeX() + w.getRelativeY())
.reversed()
.thenComparing(Widget::getId)
.reversed())
.findFirst().get();
x = 4;
y = 4;
}
picker = parent.createChild(-1, WidgetType.GRAPHIC);
log.info("Picker is {}.{} [{}]", WidgetInfo.TO_GROUP(picker.getId()), WidgetInfo.TO_CHILD(picker.getId()), picker.getIndex());
picker.setSpriteId(SpriteID.MOBILE_FINGER_ON_INTERFACE);
picker.setOriginalWidth(15);
picker.setOriginalHeight(17);
picker.setOriginalX(x);
picker.setOriginalY(y);
picker.revalidate();
picker.setTargetVerb("Select");
picker.setName("Pick");
picker.setClickMask(WidgetConfig.USE_WIDGET | WidgetConfig.USE_ITEM);
picker.setNoClickThrough(true);
picker.setOnTargetEnterListener((JavaScriptCallback) ev ->
{
pickerSelected = true;
picker.setOpacity(30);
client.setAllWidgetsAreOpTargetable(true);
});
picker.setOnTargetLeaveListener((JavaScriptCallback) ev -> onPickerDeselect());
}
private void onPickerDeselect()
{
client.setAllWidgetsAreOpTargetable(false);
picker.setOpacity(0);
pickerSelected = false;
}
private void onMenuOptionClicked(MenuOptionClicked ev)
{
if (!pickerSelected)
{
return;
}
onPickerDeselect();
client.setSpellSelected(false);
ev.consume();
Object target = getWidgetOrWidgetItemForMenuOption(ev.getMenuOpcode().getId(), ev.getParam0(), ev.getParam1());
if (target == null)
{
return;
}
if (target instanceof WidgetItem)
{
WidgetItem iw = (WidgetItem) target;
setSelectedWidget(iw.getWidget(), iw.getIndex(), true);
}
else
{
setSelectedWidget((Widget) target, -1, true);
}
}
private void onMenuEntryAdded(MenuEntryAdded event)
{
if (!pickerSelected)
{
return;
}
MenuEntry[] menuEntries = client.getMenuEntries();
for (int i = 0; i < menuEntries.length; i++)
{
MenuEntry entry = menuEntries[i];
if (entry.getOpcode() != MenuOpcode.ITEM_USE_ON_WIDGET.getId()
&& entry.getOpcode() != MenuOpcode.SPELL_CAST_ON_WIDGET.getId())
{
continue;
}
String name = WidgetInfo.TO_GROUP(entry.getParam1()) + "." + WidgetInfo.TO_CHILD(entry.getParam1());
if (entry.getParam0() != -1)
{
name += " [" + entry.getParam0() + "]";
}
Color color = colorForWidget(i, menuEntries.length);
entry.setTarget(ColorUtil.wrapWithColorTag(name, color));
}
client.setMenuEntries(menuEntries);
}
Color colorForWidget(int index, int length)
{
float h = SELECTED_WIDGET_HUE + .1f + (.8f / length) * index;
return Color.getHSBColor(h, 1, 1);
}
Object getWidgetOrWidgetItemForMenuOption(int type, int param0, int param1)
{
if (type == MenuOpcode.SPELL_CAST_ON_WIDGET.getId())
{
Widget w = client.getWidget(WidgetInfo.TO_GROUP(param1), WidgetInfo.TO_CHILD(param1));
if (param0 != -1)
{
w = w.getChild(param0);
}
return w;
}
else if (type == MenuOpcode.ITEM_USE_ON_WIDGET.getId())
{
Widget w = client.getWidget(WidgetInfo.TO_GROUP(param1), WidgetInfo.TO_CHILD(param1));
return w.getWidgetItem(param0);
}
return null;
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2018 Abex
* Copyright (c) 2017, Kronos <https://github.com/KronosDesign>
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* 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.devtools;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.MenuEntry;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
@Singleton
public class WidgetInspectorOverlay extends Overlay
{
private final Client client;
private final WidgetInspector inspector;
@Inject
public WidgetInspectorOverlay(
Client client,
WidgetInspector inspector
)
{
this.client = client;
this.inspector = inspector;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
setPriority(OverlayPriority.HIGHEST);
}
@Override
public Dimension render(Graphics2D g)
{
Widget w = inspector.getSelectedWidget();
if (w != null)
{
Object wiw = w;
if (inspector.getSelectedItem() != -1)
{
wiw = w.getWidgetItem(inspector.getSelectedItem());
}
renderWiw(g, wiw, WidgetInspector.SELECTED_WIDGET_COLOR);
}
if (inspector.isPickerSelected())
{
boolean menuOpen = client.isMenuOpen();
MenuEntry[] entries = client.getMenuEntries();
for (int i = menuOpen ? 0 : entries.length - 1; i < entries.length; i++)
{
MenuEntry e = entries[i];
Object wiw = inspector.getWidgetOrWidgetItemForMenuOption(e.getOpcode(), e.getParam0(), e.getParam1());
if (wiw == null)
{
continue;
}
Color color = inspector.colorForWidget(i, entries.length);
renderWiw(g, wiw, color);
}
}
return null;
}
private void renderWiw(Graphics2D g, Object wiw, Color color)
{
g.setColor(color);
if (wiw instanceof WidgetItem)
{
WidgetItem wi = (WidgetItem) wiw;
Rectangle bounds = wi.getCanvasBounds();
g.draw(bounds);
String text = wi.getId() + "";
FontMetrics fm = g.getFontMetrics();
Rectangle2D textBounds = fm.getStringBounds(text, g);
int textX = (int) (bounds.getX() + (bounds.getWidth() / 2) - (textBounds.getWidth() / 2));
int textY = (int) (bounds.getY() + (bounds.getHeight() / 2) + (textBounds.getHeight() / 2));
g.setColor(Color.BLACK);
g.drawString(text, textX + 1, textY + 1);
g.setColor(Color.ORANGE);
g.drawString(text, textX, textY);
}
else
{
Widget w = (Widget) wiw;
g.draw(w.getBounds());
}
}
}

View File

@@ -36,6 +36,7 @@ import net.runelite.api.Client;
import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.TileObject;
import net.runelite.api.WallObject;
import net.runelite.client.graphics.ModelOutlineRenderer;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
@@ -107,6 +108,11 @@ class ObjectIndicatorsOverlay extends Overlay
{
polygon = ((GameObject) object).getConvexHull();
}
else if (object instanceof WallObject)
{
polygon = ((WallObject) object).getConvexHull();
polygon2 = ((WallObject) object).getConvexHull2();
}
else if (object instanceof DecorativeObject)
{
polygon = ((DecorativeObject) object).getConvexHull();

View File

@@ -38,21 +38,25 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import static net.runelite.api.Constants.REGION_SIZE;
import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import net.runelite.api.GroundObject;
import net.runelite.api.MenuOpcode;
import net.runelite.api.MenuEntry;
import net.runelite.api.ObjectDefinition;
import net.runelite.api.Scene;
import net.runelite.api.Tile;
import net.runelite.api.TileObject;
import net.runelite.api.WallObject;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.DecorativeObjectDespawned;
@@ -61,8 +65,13 @@ import net.runelite.api.events.FocusChanged;
import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GroundObjectDespawned;
import net.runelite.api.events.GroundObjectSpawned;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.WallObjectChanged;
import net.runelite.api.events.WallObjectDespawned;
import net.runelite.api.events.WallObjectSpawned;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.input.KeyListener;
@@ -78,6 +87,7 @@ import net.runelite.client.ui.overlay.OverlayManager;
enabledByDefault = false
)
@Singleton
@Slf4j
public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
{
private static final String CONFIG_GROUP = "objectindicators";
@@ -152,10 +162,15 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
{
eventbus.subscribe(ConfigChanged.class, this, this::onConfigChanged);
eventbus.subscribe(FocusChanged.class, this, this::onFocusChanged);
eventbus.subscribe(WallObjectSpawned.class, this, this::onWallObjectSpawned);
eventbus.subscribe(WallObjectChanged.class, this, this::onWallObjectChanged);
eventbus.subscribe(WallObjectDespawned.class, this, this::onWallObjectDespawned);
eventbus.subscribe(GameObjectSpawned.class, this, this::onGameObjectSpawned);
eventbus.subscribe(DecorativeObjectSpawned.class, this, this::onDecorativeObjectSpawned);
eventbus.subscribe(GameObjectDespawned.class, this, this::onGameObjectDespawned);
eventbus.subscribe(DecorativeObjectDespawned.class, this, this::onDecorativeObjectDespawned);
eventbus.subscribe(GroundObjectDespawned.class, this, this::onGroundObjectDespawned);
eventbus.subscribe(GroundObjectSpawned.class, this, this::onGroundObjectSpawned);
eventbus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventbus.subscribe(MenuOptionClicked.class, this, this::onMenuOptionClicked);
eventbus.subscribe(MenuEntryAdded.class, this, this::onMenuEntryAdded);
@@ -193,6 +208,25 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
}
}
private void onWallObjectSpawned(WallObjectSpawned event)
{
checkObjectPoints(event.getWallObject());
}
private void onWallObjectChanged(WallObjectChanged event)
{
WallObject previous = event.getPrevious();
WallObject wallObject = event.getWallObject();
objects.remove(previous);
checkObjectPoints(wallObject);
}
private void onWallObjectDespawned(WallObjectDespawned event)
{
objects.remove(event.getWallObject());
}
private void onGameObjectSpawned(GameObjectSpawned event)
{
final GameObject eventObject = event.getGameObject();
@@ -215,6 +249,18 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
objects.remove(event.getDecorativeObject());
}
private void onGroundObjectSpawned(GroundObjectSpawned groundObjectSpawned)
{
final GroundObject groundObject = groundObjectSpawned.getGroundObject();
checkObjectPoints(groundObject);
}
private void onGroundObjectDespawned(GroundObjectDespawned groundObjectDespawned)
{
GroundObject groundObject = groundObjectDespawned.getGroundObject();
objects.remove(groundObject);
}
private void onGameStateChanged(GameStateChanged gameStateChanged)
{
GameState gameState = gameStateChanged.getGameState();
@@ -283,9 +329,13 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
return;
}
ObjectDefinition objectDefinition = client.getObjectDefinition(object.getId());
// object.getId() is always the base object id, getObjectComposition transforms it to
// the correct object we see
ObjectDefinition objectDefinition = getObjectDefinition(object.getId());
String name = objectDefinition.getName();
if (Strings.isNullOrEmpty(name))
// Name is probably never "null" - however prevent adding it if it is, as it will
// become ambiguous as objects with no name are assigned name "null"
if (Strings.isNullOrEmpty(name) || name.equals("null"))
{
return;
}
@@ -306,11 +356,15 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
for (ObjectPoint objectPoint : objectPoints)
{
if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX()
&& (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY()
&& objectPoint.getName().equals(client.getObjectDefinition(object.getId()).getName()))
&& (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY())
{
objects.add(object);
break;
// Transform object to get the name which matches against what we've stored
if (objectPoint.getName().equals(getObjectDefinition(object.getId()).getName()))
{
log.debug("Marking object {} due to matching {}", object, objectPoint);
objects.add(object);
break;
}
}
}
}
@@ -324,42 +378,65 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
final GameObject[] tileGameObjects = tile.getGameObjects();
final DecorativeObject tileDecorativeObject = tile.getDecorativeObject();
final WallObject tileWallObject = tile.getWallObject();
final GroundObject groundObject = tile.getGroundObject();
if (tileDecorativeObject != null && tileDecorativeObject.getId() == id)
if (objectIdEquals(tileWallObject, id))
{
return tileWallObject;
}
if (objectIdEquals(tileDecorativeObject, id))
{
return tileDecorativeObject;
}
if (objectIdEquals(groundObject, id))
{
return groundObject;
}
for (GameObject object : tileGameObjects)
{
if (object == null)
{
continue;
}
if (object.getId() == id)
if (objectIdEquals(object, id))
{
return object;
}
// Check impostors
final ObjectDefinition comp = client.getObjectDefinition(object.getId());
if (comp.getImpostorIds() != null)
{
for (int impostorId : comp.getImpostorIds())
{
if (impostorId == id)
{
return object;
}
}
}
}
return null;
}
private boolean objectIdEquals(TileObject tileObject, int id)
{
if (tileObject == null)
{
return false;
}
if (tileObject.getId() == id)
{
return true;
}
// Menu action EXAMINE_OBJECT sends the transformed object id, not the base id, unlike
// all of the GAME_OBJECT_OPTION actions, so check the id against the impostor ids
final ObjectDefinition comp = client.getObjectDefinition(tileObject.getId());
if (comp.getImpostorIds() != null)
{
for (int impostorId : comp.getImpostorIds())
{
if (impostorId == id)
{
return true;
}
}
}
return false;
}
private void markObject(String name, final TileObject object)
{
if (object == null)
@@ -382,11 +459,13 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
{
objectPoints.remove(point);
objects.remove(object);
log.debug("Unmarking object: {}", point);
}
else
{
objectPoints.add(point);
objects.add(object);
log.debug("Marking object: {}", point);
}
savePoints(regionId, objectPoints);
@@ -414,11 +493,18 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
return null;
}
return GSON.fromJson(json, new TypeToken<Set<ObjectPoint>>()
Set<ObjectPoint> points = GSON.fromJson(json, new TypeToken<Set<ObjectPoint>>()
{
}.getType());
// Prior to multiloc support the plugin would mark objects named "null", which breaks
// in most cases due to the specific object being identified being ambiguous, so remove
// them
return points.stream()
.filter(point -> !point.getName().equals("null"))
.collect(Collectors.toSet());
}
private void onConfigChanged(ConfigChanged event)
{
if (!event.getGroup().equals("objectindicators"))
@@ -436,4 +522,10 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
this.objectMarkerColor = config.objectMarkerColor();
this.objectMarkerAlpha = config.objectMarkerAlpha();
}
private ObjectDefinition getObjectDefinition(int id)
{
ObjectDefinition objectComposition = client.getObjectDefinition(id);
return objectComposition.getImpostorIds() == null ? objectComposition : objectComposition.getImpostor();
}
}

View File

@@ -25,13 +25,14 @@
package net.runelite.client.plugins.wiki;
import com.google.common.primitives.Ints;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Arrays;
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.MenuEntry;
import net.runelite.api.MenuOpcode;
import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition;
@@ -40,6 +41,7 @@ import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.util.Text;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
@@ -55,7 +57,6 @@ 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.api.util.Text;
import okhttp3.HttpUrl;
@Slf4j
@@ -82,9 +83,6 @@ public class WikiPlugin extends Plugin
private static final String MENUOP_QUICKGUIDE = "Quick Guide";
private static final String MENUOP_WIKI = "Wiki";
private static final Pattern SKILL_REGEX = Pattern.compile("([A-Za-z]+) guide");
private static final Pattern DIARY_REGEX = Pattern.compile("([A-Za-z &]+) Journal");
@Inject
private SpriteManager spriteManager;
@@ -177,12 +175,14 @@ public class WikiPlugin extends Plugin
icon.setOriginalHeight(16);
icon.setTargetVerb("Lookup");
icon.setName("Wiki");
icon.setClickMask(WidgetConfig.USE_GROUND_ITEM | WidgetConfig.USE_ITEM | WidgetConfig.USE_NPC | WidgetConfig.USE_OBJECT);
icon.setClickMask(WidgetConfig.USE_GROUND_ITEM | WidgetConfig.USE_ITEM | WidgetConfig.USE_NPC
| WidgetConfig.USE_OBJECT | WidgetConfig.USE_WIDGET);
icon.setNoClickThrough(true);
icon.setOnTargetEnterListener((JavaScriptCallback) ev ->
{
wikiSelected = true;
icon.setSpriteId(WikiSprite.WIKI_SELECTED_ICON.getSpriteId());
client.setAllWidgetsAreOpTargetable(true);
});
icon.setAction(5, "Search"); // Start at option 5 so the target op is ontop
icon.setOnOpListener((JavaScriptCallback) ev ->
@@ -199,6 +199,8 @@ public class WikiPlugin extends Plugin
private void onDeselect()
{
client.setAllWidgetsAreOpTargetable(false);
wikiSelected = false;
if (icon != null)
{
@@ -208,6 +210,7 @@ public class WikiPlugin extends Plugin
private void onMenuOptionClicked(MenuOptionClicked ev)
{
optarget:
if (wikiSelected)
{
onDeselect();
@@ -221,6 +224,9 @@ public class WikiPlugin extends Plugin
switch (ev.getMenuOpcode())
{
case RUNELITE:
// This is a quest widget op
break optarget;
case CANCEL:
return;
case ITEM_USE_ON_WIDGET:
@@ -255,6 +261,18 @@ public class WikiPlugin extends Plugin
location = WorldPoint.fromScene(client, ev.getParam0(), ev.getParam1(), client.getPlane());
break;
}
case SPELL_CAST_ON_WIDGET:
Widget w = getWidget(ev.getParam1(), ev.getParam0());
if (w.getType() == WidgetType.GRAPHIC && w.getItemId() != -1)
{
type = "item";
id = itemManager.canonicalize(w.getItemId());
name = itemManager.getItemDefinition(id).getName();
location = null;
break;
}
// fallthrough
default:
log.info("Unknown menu option: {} {} {}", ev, ev.getMenuOpcode(), ev.getMenuOpcode() == MenuOpcode.CANCEL);
return;
@@ -303,25 +321,11 @@ public class WikiPlugin extends Plugin
LinkBrowser.browse(ub.build().toString());
break;
case MENUOP_WIKI:
Matcher skillRegex = WikiPlugin.SKILL_REGEX.matcher(Text.removeTags(ev.getTarget()));
Matcher diaryRegex = WikiPlugin.DIARY_REGEX.matcher(Text.removeTags(ev.getTarget()));
if (skillRegex.find())
{
LinkBrowser.browse(WIKI_BASE.newBuilder()
.addPathSegment("w")
.addPathSegment(skillRegex.group(1))
.addQueryParameter(UTM_SOURCE_KEY, UTM_SOURCE_VALUE)
.build().toString());
}
else if (diaryRegex.find())
{
LinkBrowser.browse(WIKI_BASE.newBuilder()
.addPathSegment("w")
.addPathSegment(diaryRegex.group(1) + " Diary")
.addQueryParameter(UTM_SOURCE_KEY, UTM_SOURCE_VALUE)
.build().toString());
}
LinkBrowser.browse(WIKI_BASE.newBuilder()
.addPathSegment("w")
.addPathSegment(Text.removeTags(ev.getTarget()))
.addQueryParameter(UTM_SOURCE_KEY, UTM_SOURCE_VALUE)
.build().toString());
}
}
}
@@ -332,16 +336,51 @@ public class WikiPlugin extends Plugin
.build();
}
private Widget getWidget(int wid, int index)
{
Widget w = client.getWidget(WidgetInfo.TO_GROUP(wid), WidgetInfo.TO_CHILD(wid));
if (index != -1)
{
w = w.getChild(index);
}
return w;
}
private void onMenuEntryAdded(MenuEntryAdded event)
{
int widgetIndex = event.getParam0();
int widgetID = event.getParam1();
MenuEntry[] menuEntries = client.getMenuEntries();
if (Ints.contains(QUESTLIST_WIDGET_IDS, widgetID) && "Read Journal:".equals(event.getOption()))
if (wikiSelected && event.getOpcode() == MenuOpcode.SPELL_CAST_ON_WIDGET.getId())
{
Widget w = getWidget(widgetID, widgetIndex);
if (!(w.getType() == WidgetType.GRAPHIC && w.getItemId() != -1))
{
// we don't support this widget
// remove the last SPELL_CAST_ON_WIDGET; we can't blindly remove the top action because some other
// plugin might have added something on this same event, and we probably shouldn't remove that instead
MenuEntry[] oldEntries = menuEntries;
menuEntries = Arrays.copyOf(menuEntries, menuEntries.length - 1);
for (int ourEntry = oldEntries.length - 1;
ourEntry >= 2 && oldEntries[oldEntries.length - 1].getOpcode() != MenuOpcode.SPELL_CAST_ON_WIDGET.getId();
ourEntry--)
{
menuEntries[ourEntry - 1] = oldEntries[ourEntry];
}
client.setMenuEntries(menuEntries);
}
}
if (Ints.contains(QUESTLIST_WIDGET_IDS, widgetID)
&& ((wikiSelected && widgetIndex != -1) || "Read Journal:".equals(event.getOption())))
{
Widget w = getWidget(widgetID, widgetIndex);
String target = w.getName();
client.insertMenuItem(
MENUOP_QUICKGUIDE,
event.getTarget(),
target,
MenuOpcode.RUNELITE.getId(),
0,
widgetIndex,
@@ -351,7 +390,7 @@ public class WikiPlugin extends Plugin
client.insertMenuItem(
MENUOP_GUIDE,
event.getTarget(),
target,
MenuOpcode.RUNELITE.getId(),
0,
widgetIndex,
@@ -360,12 +399,52 @@ public class WikiPlugin extends Plugin
);
}
if ((WidgetInfo.TO_GROUP(widgetID) == WidgetID.SKILLS_GROUP_ID && event.getOption().startsWith("View"))
|| (WidgetInfo.TO_GROUP(widgetID) == WidgetID.ACHIEVEMENT_DIARY_GROUP_ID && event.getOption().startsWith("Open")))
if (widgetID == WidgetInfo.ACHIEVEMENT_DIARY_CONTAINER.getId())
{
Widget w = getWidget(widgetID, widgetIndex);
if (w.getActions() == null)
{
return;
}
String action = Stream.of(w.getActions())
.filter(s -> s != null && !s.isEmpty())
.findFirst().orElse(null);
if (action == null)
{
return;
}
client.insertMenuItem(
MENUOP_WIKI,
event.getOption().replace("View ", "").replace("Open ", ""),
action.replace("Open ", "").replace("Journal", "Diary"),
MenuOpcode.RUNELITE.getId(),
0,
widgetIndex,
widgetID,
false
);
}
if (WidgetInfo.TO_GROUP(widgetID) == WidgetInfo.SKILLS_CONTAINER.getGroupId())
{
Widget w = getWidget(widgetID, widgetIndex);
if (w.getParentId() != WidgetInfo.SKILLS_CONTAINER.getId())
{
return;
}
String action = Stream.of(w.getActions())
.filter(s -> s != null && !s.isEmpty())
.findFirst().orElse(null);
if (action == null)
{
return;
}
client.insertMenuItem(
MENUOP_WIKI,
action.replace("View ", "").replace("Guide ", ""),
MenuOpcode.RUNELITE.getId(),
event.getIdentifier(),
widgetIndex,

View File

@@ -316,7 +316,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
graphics.setColor(previous);
}
if (menuEntries == null && !client.isMenuOpen() && bounds.contains(mouse))
if (menuEntries == null && !client.isMenuOpen() && !client.isSpellSelected() && bounds.contains(mouse))
{
menuEntries = createRightClickMenuEntries(overlay);
}