Merge pull request #5751 from Abextm/widget-assertions

Run unsafe widget accesses on client thread
This commit is contained in:
Adam
2018-10-04 10:27:43 -04:00
committed by GitHub
5 changed files with 80 additions and 48 deletions

View File

@@ -32,6 +32,7 @@ import net.runelite.api.Client;
import net.runelite.api.events.GameTick; import net.runelite.api.events.GameTick;
import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
@@ -46,6 +47,9 @@ public class BankValuePlugin extends Plugin
@Inject @Inject
private Client client; private Client client;
@Inject
private ClientThread clientThread;
@Inject @Inject
private BankCalculation bankCalculation; private BankCalculation bankCalculation;
@@ -61,7 +65,7 @@ public class BankValuePlugin extends Plugin
@Override @Override
protected void shutDown() protected void shutDown()
{ {
bankTitle.reset(); clientThread.invokeLater(bankTitle::reset);
} }
@Subscribe @Subscribe

View File

@@ -24,24 +24,45 @@
*/ */
package net.runelite.client.plugins.devtools; package net.runelite.client.plugins.devtools;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.Widget;
import net.runelite.client.callback.ClientThread;
public class WidgetInfoTableModel extends AbstractTableModel public class WidgetInfoTableModel extends AbstractTableModel
{ {
@Inject
private ClientThread clientThread;
private static final int COL_FIELD = 0; private static final int COL_FIELD = 0;
private static final int COL_VALUE = 1; private static final int COL_VALUE = 1;
private static final List<WidgetField> fields = populateWidgetFields(); private static final List<WidgetField> fields = populateWidgetFields();
private Widget widget = null; private Widget widget = null;
private Map<WidgetField, Object> values = null;
public void setWidget(Widget w) public void setWidget(Widget w)
{ {
this.widget = w; clientThread.invoke(() ->
fireTableStructureChanged(); {
Map<WidgetField, Object> newValues = w == null ? null : fields.stream().collect(ImmutableMap.toImmutableMap(
Function.identity(),
i -> i.getValue(w)
));
SwingUtilities.invokeLater(() ->
{
widget = w;
values = newValues;
fireTableStructureChanged();
});
});
} }
@Override @Override
@@ -67,11 +88,11 @@ public class WidgetInfoTableModel extends AbstractTableModel
@Override @Override
public int getRowCount() public int getRowCount()
{ {
if (widget == null) if (values == null)
{ {
return 0; return 0;
} }
return fields.size(); return values.size();
} }
@Override @Override
@@ -83,7 +104,7 @@ public class WidgetInfoTableModel extends AbstractTableModel
case COL_FIELD: case COL_FIELD:
return field.getName(); return field.getName();
case COL_VALUE: case COL_VALUE:
return field.getValue(widget); return values.get(field);
default: default:
return null; return null;
} }
@@ -104,7 +125,11 @@ public class WidgetInfoTableModel extends AbstractTableModel
public void setValueAt(Object value, int rowIndex, int columnIndex) public void setValueAt(Object value, int rowIndex, int columnIndex)
{ {
WidgetField<?> field = fields.get(rowIndex); WidgetField<?> field = fields.get(rowIndex);
field.setValue(widget, value); clientThread.invoke(() ->
{
field.setValue(widget, value);
setWidget(widget);
});
} }
private static List<WidgetField> populateWidgetFields() private static List<WidgetField> populateWidgetFields()

View File

@@ -36,7 +36,6 @@ import java.awt.event.WindowEvent;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
import javax.swing.JFrame; import javax.swing.JFrame;
@@ -45,7 +44,7 @@ import javax.swing.JScrollPane;
import javax.swing.JSplitPane; import javax.swing.JSplitPane;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.JTree; import javax.swing.JTree;
import javax.swing.SwingWorker; import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeModel;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -54,12 +53,14 @@ import net.runelite.api.events.ConfigChanged;
import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetItem; import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.ClientUI;
@Slf4j @Slf4j
class WidgetInspector extends JFrame class WidgetInspector extends JFrame
{ {
private final Client client; private final Client client;
private final ClientThread clientThread;
private final DevToolsPlugin plugin; private final DevToolsPlugin plugin;
private final DevToolsConfig config; private final DevToolsConfig config;
@@ -70,10 +71,11 @@ class WidgetInspector extends JFrame
private static final Map<Integer, WidgetInfo> widgetIdMap = new HashMap<>(); private static final Map<Integer, WidgetInfo> widgetIdMap = new HashMap<>();
@Inject @Inject
WidgetInspector(DevToolsPlugin plugin, Client client, WidgetInfoTableModel infoTableModel, DevToolsConfig config, EventBus eventBus) WidgetInspector(DevToolsPlugin plugin, Client client, ClientThread clientThread, WidgetInfoTableModel infoTableModel, DevToolsConfig config, EventBus eventBus)
{ {
this.plugin = plugin; this.plugin = plugin;
this.client = client; this.client = client;
this.clientThread = clientThread;
this.infoTableModel = infoTableModel; this.infoTableModel = infoTableModel;
this.config = config; this.config = config;
@@ -157,45 +159,31 @@ class WidgetInspector extends JFrame
private void refreshWidgets() private void refreshWidgets()
{ {
new SwingWorker<DefaultMutableTreeNode, Void>() clientThread.invokeLater(() ->
{ {
@Override Widget[] rootWidgets = client.getWidgetRoots();
protected DefaultMutableTreeNode doInBackground() throws Exception DefaultMutableTreeNode root = new DefaultMutableTreeNode();
{
Widget[] rootWidgets = client.getWidgetRoots();
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
plugin.currentWidget = null;
plugin.itemIndex = -1;
for (Widget widget : rootWidgets)
{
DefaultMutableTreeNode childNode = addWidget("R", widget);
if (childNode != null)
{
root.add(childNode);
}
}
SwingUtilities.invokeLater(() ->
{
plugin.currentWidget = null; plugin.currentWidget = null;
plugin.itemIndex = -1; plugin.itemIndex = -1;
refreshInfo();
for (Widget widget : rootWidgets) widgetTree.setModel(new DefaultTreeModel(root));
{ });
DefaultMutableTreeNode childNode = addWidget("R", widget); });
if (childNode != null)
{
root.add(childNode);
}
}
return root;
}
@Override
protected void done()
{
try
{
plugin.currentWidget = null;
plugin.itemIndex = -1;
refreshInfo();
widgetTree.setModel(new DefaultTreeModel(get()));
}
catch (InterruptedException | ExecutionException ex)
{
throw new RuntimeException(ex);
}
}
}.execute();
} }
private DefaultMutableTreeNode addWidget(String type, Widget widget) private DefaultMutableTreeNode addWidget(String type, Widget widget)

View File

@@ -169,10 +169,13 @@ public class MotherlodePlugin extends Plugin
Widget sack = client.getWidget(WidgetInfo.MOTHERLODE_MINE); Widget sack = client.getWidget(WidgetInfo.MOTHERLODE_MINE);
if (sack != null && sack.isHidden()) clientThread.invokeLater(() ->
{ {
sack.setHidden(false); if (sack != null && sack.isHidden())
} {
sack.setHidden(false);
}
});
} }
public MotherlodeSession getSession() public MotherlodeSession getSession()

View File

@@ -113,6 +113,8 @@ public abstract class RSWidgetMixin implements RSWidget
@Override @Override
public int getParentId() public int getParentId()
{ {
assert client.isClientThread();
int rsParentId = getRSParentId(); int rsParentId = getRSParentId();
if (rsParentId != -1) if (rsParentId != -1)
{ {
@@ -198,6 +200,8 @@ public abstract class RSWidgetMixin implements RSWidget
@Override @Override
public boolean isHidden() public boolean isHidden()
{ {
assert client.isClientThread();
if (isSelfHidden()) if (isSelfHidden())
{ {
return true; return true;
@@ -359,6 +363,8 @@ public abstract class RSWidgetMixin implements RSWidget
@Override @Override
public Widget[] getNestedChildren() public Widget[] getNestedChildren()
{ {
assert client.isClientThread();
if (getRSParentId() == getId()) if (getRSParentId() == getId())
{ {
// This is a dynamic widget, so it can't have nested children // This is a dynamic widget, so it can't have nested children
@@ -494,6 +500,8 @@ public abstract class RSWidgetMixin implements RSWidget
@Override @Override
public Widget createChild(int index, int type) public Widget createChild(int index, int type)
{ {
assert client.isClientThread();
RSWidget w = client.createWidget(); RSWidget w = client.createWidget();
w.setType(type); w.setType(type);
w.setParentId(getId()); w.setParentId(getId());
@@ -537,6 +545,8 @@ public abstract class RSWidgetMixin implements RSWidget
@Override @Override
public void revalidate() public void revalidate()
{ {
assert client.isClientThread();
client.revalidateWidget(this); client.revalidateWidget(this);
} }
@@ -544,6 +554,8 @@ public abstract class RSWidgetMixin implements RSWidget
@Override @Override
public void revalidateScroll() public void revalidateScroll()
{ {
assert client.isClientThread();
client.revalidateWidget(this); client.revalidateWidget(this);
client.revalidateWidgetScroll(client.getWidgets()[TO_GROUP(this.getId())], this, false); client.revalidateWidgetScroll(client.getWidgets()[TO_GROUP(this.getId())], this, false);
} }