From 799f8b1266cde95abce8df04d91b80c05eb33dea Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 26 Jun 2018 15:14:53 -0400 Subject: [PATCH] Calculate and store widget parent id and position when the interfaces are rendered This removes the need to calculate widget bounds and parent on demand by traversing up the widget tree. --- .../main/java/net/runelite/api/Client.java | 9 - .../reorderprayers/ReorderPrayersPlugin.java | 3 +- .../net/runelite/mixins/RSClientMixin.java | 61 +++++-- .../net/runelite/mixins/RSWidgetMixin.java | 159 ++++++++---------- .../java/net/runelite/rs/api/RSClient.java | 9 + .../java/net/runelite/rs/api/RSWidget.java | 6 + 6 files changed, 137 insertions(+), 110 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 6d786e46c4..3dc8a3a4c2 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -412,15 +412,6 @@ public interface Client extends GameEngine */ Widget getWidget(WidgetInfo widget); - /** - * Gets an array of widgets that correspond to the passed group ID. - * - * @param groupId the group ID - * @return the widget group - * @see net.runelite.api.widgets.WidgetID - */ - Widget[] getGroup(int groupId); - /** * Gets a widget by its raw group ID and child ID. *

diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/reorderprayers/ReorderPrayersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/reorderprayers/ReorderPrayersPlugin.java index 86615d1c5c..8d7690579a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/reorderprayers/ReorderPrayersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/reorderprayers/ReorderPrayersPlugin.java @@ -36,14 +36,13 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.HashTable; -import net.runelite.api.Node; import net.runelite.api.Prayer; import net.runelite.api.WidgetNode; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.DraggingWidgetChanged; import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.WidgetMenuOptionClicked; import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.events.WidgetMenuOptionClicked; import net.runelite.api.widgets.Widget; import static net.runelite.api.widgets.WidgetConfig.DRAG; import static net.runelite.api.widgets.WidgetConfig.DRAG_ON; diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java index ae63a28ae8..48b37398e1 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -35,6 +35,7 @@ import net.runelite.api.Friend; import net.runelite.api.GameState; import net.runelite.api.GrandExchangeOffer; import net.runelite.api.GraphicsObject; +import net.runelite.api.HashTable; import net.runelite.api.HintArrowType; import net.runelite.api.IndexedSprite; import net.runelite.api.InventoryID; @@ -61,6 +62,7 @@ import net.runelite.api.SpritePixels; import net.runelite.api.Tile; import net.runelite.api.VarPlayer; import net.runelite.api.Varbits; +import net.runelite.api.WidgetNode; import net.runelite.api.WorldType; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; @@ -321,9 +323,9 @@ public abstract class RSClientMixin implements RSClient { int topGroup = getWidgetRoot(); List widgets = new ArrayList(); - for (Widget widget : getWidgets()[topGroup]) + for (RSWidget widget : getWidgets()[topGroup]) { - if (widget != null && widget.getParentId() == -1) + if (widget != null && widget.getRSParentId() == -1) { widgets.add(widget); } @@ -343,7 +345,7 @@ public abstract class RSClientMixin implements RSClient @Inject @Override - public Widget[] getGroup(int groupId) + public RSWidget[] getGroup(int groupId) { RSWidget[][] widgets = getWidgets(); @@ -352,15 +354,7 @@ public abstract class RSClientMixin implements RSClient return null; } - List w = new ArrayList(); - for (Widget widget : widgets[groupId]) - { - if (widget != null) - { - w.add(widget); - } - } - return w.toArray(new Widget[w.size()]); + return widgets[groupId]; } @Inject @@ -564,7 +558,7 @@ public abstract class RSClientMixin implements RSClient for (Node node = head.getNext(); node != head; node = node.getNext()) { - graphicsObjects.add((GraphicsObject)node); + graphicsObjects.add((GraphicsObject) node); } return graphicsObjects; @@ -1099,4 +1093,45 @@ public abstract class RSClientMixin implements RSClient { callbacks.clientMainLoop(); } + + @MethodHook("gameDraw") + @Inject + public static void gameDraw(Widget[] widgets, int parentId, int var2, int var3, int var4, int var5, int x, int y, int var8) + { + for (Widget rlWidget : widgets) + { + RSWidget widget = (RSWidget) rlWidget; + if (widget == null) + { + continue; + } + + if (widget.getRSParentId() == parentId) + { + if (parentId != -1) + { + widget.setRenderParentId(parentId); + } + widget.setRenderX(x + widget.getRelativeX()); + widget.setRenderY(y + widget.getRelativeY()); + } + + HashTable componentTable = client.getComponentTable(); + WidgetNode childNode = componentTable.get(widget.getId()); + if (childNode != null) + { + int widgetId = widget.getId(); + int groupId = childNode.getId(); + RSWidget[] children = client.getWidgets()[groupId]; + + for (RSWidget child : children) + { + if (child.getRSParentId() == -1) + { + child.setRenderParentId(widgetId); + } + } + } + } + } } \ No newline at end of file diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java index 14a44ec564..3d226d3840 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java @@ -28,7 +28,7 @@ import java.awt.Rectangle; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import net.runelite.api.Node; +import net.runelite.api.HashTable; import net.runelite.api.Point; import net.runelite.api.WidgetNode; import net.runelite.api.events.WidgetHiddenChanged; @@ -42,8 +42,6 @@ import static net.runelite.api.widgets.WidgetInfo.TO_CHILD; import static net.runelite.api.widgets.WidgetInfo.TO_GROUP; import net.runelite.api.widgets.WidgetItem; import net.runelite.rs.api.RSClient; -import net.runelite.rs.api.RSHashTable; -import net.runelite.rs.api.RSNode; import net.runelite.rs.api.RSWidget; @Mixin(RSWidget.class) @@ -57,6 +55,44 @@ public abstract class RSWidgetMixin implements RSWidget @Inject private static int rl$widgetLastPosChanged; + @Inject + private int rl$parentId; + + @Inject + private int rl$x; + + @Inject + private int rl$y; + + @Inject + RSWidgetMixin() + { + rl$parentId = -1; + rl$x = -1; + rl$y = -1; + } + + @Inject + @Override + public void setRenderParentId(int parentId) + { + rl$parentId = parentId; + } + + @Inject + @Override + public void setRenderX(int x) + { + rl$x = x; + } + + @Inject + @Override + public void setRenderY(int y) + { + rl$y = y; + } + @Inject @Override public Widget getParent() @@ -74,34 +110,27 @@ public abstract class RSWidgetMixin implements RSWidget @Override public int getParentId() { - int parentId = getRSParentId(); - if (parentId != -1) - { - return parentId; - } + int parentId = rl$parentId; - int groupId = TO_GROUP(getId()); - RSHashTable componentTable = client.getComponentTable(); - RSNode[] buckets = componentTable.getBuckets(); - for (int i = 0; i < buckets.length; ++i) + if (parentId != -1 && getRSParentId() == -1) { - Node node = buckets[i]; + // if this happens, the widget is or was nested. + // rl$parentId is updated when drawing, but will not be updated when + // the widget is no longer reachable in the tree, leaving + // parent id potentially incorrect - // It looks like the first node in the bucket is always - // a sentinel - Node cur = node.getNext(); - while (cur != node) + // check the parent in the component table + HashTable componentTable = client.getComponentTable(); + WidgetNode widgetNode = componentTable.get(parentId); + if (widgetNode == null || widgetNode.getId() != TO_GROUP(getId())) { - WidgetNode wn = (WidgetNode) cur; - - if (groupId == wn.getId()) - { - return (int) wn.getHash(); - } - cur = cur.getNext(); + // invalidate parent + rl$parentId = -1; + return -1; } } - return -1; + + return parentId; } @Inject @@ -153,42 +182,7 @@ public abstract class RSWidgetMixin implements RSWidget @Override public Point getCanvasLocation() { - int x = 0; - int y = 0; - RSWidget cur; - - for (cur = this; cur.getParent() != null; cur = (RSWidget) cur.getParent()) - { - x += cur.getRelativeX(); - y += cur.getRelativeY(); - - x -= cur.getScrollX(); - y -= cur.getScrollY(); - } - - // cur is now the root - int[] widgetBoundsWidth = client.getWidgetPositionsX(); - int[] widgetBoundsHeight = client.getWidgetPositionsY(); - - int boundsIndex = cur.getBoundsIndex(); - if (boundsIndex != -1) - { - x += widgetBoundsWidth[boundsIndex]; - y += widgetBoundsHeight[boundsIndex]; - - if (cur.getType() > 0) - { - x += cur.getRelativeX(); - y += cur.getRelativeY(); - } - } - else - { - x += cur.getRelativeX(); - y += cur.getRelativeY(); - } - - return new Point(x, y); + return new Point(rl$x, rl$y); } @Inject @@ -285,9 +279,9 @@ public abstract class RSWidgetMixin implements RSWidget } List widgets = new ArrayList(); - for (Widget widget : children) + for (RSWidget widget : children) { - if (widget != null && widget.getParentId() == getId()) + if (widget != null && widget.getRSParentId() == getId()) { widgets.add(widget); } @@ -300,50 +294,39 @@ public abstract class RSWidgetMixin implements RSWidget public Widget[] getStaticChildren() { List widgets = new ArrayList(); - for (Widget widget : client.getGroup(TO_GROUP(getId()))) + for (RSWidget widget : client.getGroup(TO_GROUP(getId()))) { - if (widget != null && widget.getParentId() == getId()) + if (widget != null && widget.getRSParentId() == getId()) { widgets.add(widget); } } - return widgets.toArray(new Widget[widgets.size()]); + return widgets.toArray(new RSWidget[widgets.size()]); } @Inject @Override public Widget[] getNestedChildren() { - RSHashTable componentTable = client.getComponentTable(); - int group = -1; + HashTable componentTable = client.getComponentTable(); - // XXX can actually use hashtable lookup instead of table - // iteration here... - for (Node node : componentTable.getNodes()) + WidgetNode wn = componentTable.get(getId()); + if (wn == null) { - WidgetNode wn = (WidgetNode) node; - - if (wn.getHash() == getId()) - { - group = wn.getId(); - break; - } + return new RSWidget[0]; } - if (group == -1) - { - return new Widget[0]; - } + int group = wn.getId(); - List widgets = new ArrayList(); - for (Widget widget : client.getGroup(group)) + List widgets = new ArrayList(); + for (RSWidget widget : client.getGroup(group)) { - if (widget != null && widget.getParentId() == getId()) + if (widget != null && widget.getRSParentId() == -1) { widgets.add(widget); } } - return widgets.toArray(new Widget[widgets.size()]); + return widgets.toArray(new RSWidget[widgets.size()]); } @Inject @@ -373,7 +356,9 @@ public abstract class RSWidgetMixin implements RSWidget { // if the widget is hidden it will not magically unhide from its parent changing if (child == null || child.isSelfHidden()) + { continue; + } child.broadcastHidden(hidden); } @@ -386,7 +371,9 @@ public abstract class RSWidgetMixin implements RSWidget for (Widget nestedChild : nestedChildren) { if (nestedChild == null || nestedChild.isSelfHidden()) + { continue; + } ((RSWidget) nestedChild).broadcastHidden(hidden); } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index c73c8c16dd..fa7cae893e 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -156,6 +156,15 @@ public interface RSClient extends RSGameEngine, Client @Import("widgets") RSWidget[][] getWidgets(); + /** + * Gets an array of widgets that correspond to the passed group ID. + * + * @param groupId the group ID + * @return the widget group + * @see net.runelite.api.widgets.WidgetID + */ + RSWidget[] getGroup(int groupId); + @Import("region") @Override RSRegion getRegion(); diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java index d0db093204..53bfa46cfd 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java @@ -40,6 +40,12 @@ public interface RSWidget extends Widget @Override int getId(); + void setRenderParentId(int parentId); + + void setRenderX(int x); + + void setRenderY(int y); + @Import("parentId") int getRSParentId();