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.
This commit is contained in:
Adam
2018-06-26 15:14:53 -04:00
parent 8ad6f466da
commit 799f8b1266
6 changed files with 137 additions and 110 deletions

View File

@@ -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.
* <p>

View File

@@ -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;

View File

@@ -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<Widget> widgets = new ArrayList<Widget>();
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<Widget> w = new ArrayList<Widget>();
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<WidgetNode> 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);
}
}
}
}
}
}

View File

@@ -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<WidgetNode> 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<Widget> widgets = new ArrayList<Widget>();
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<Widget> widgets = new ArrayList<Widget>();
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<WidgetNode> 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<Widget> widgets = new ArrayList<Widget>();
for (Widget widget : client.getGroup(group))
List<RSWidget> widgets = new ArrayList<RSWidget>();
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);
}

View File

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

View File

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