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();