From b559a6b1af0e562f9f8c0b1e63560fc70f29fbd9 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Mon, 1 Oct 2018 23:02:05 -0600 Subject: [PATCH 1/3] Add thread assertions to Widget --- .../main/java/net/runelite/mixins/RSWidgetMixin.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 cc22c7b71f..a85d62000a 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java @@ -113,6 +113,8 @@ public abstract class RSWidgetMixin implements RSWidget @Override public int getParentId() { + assert client.isClientThread(); + int rsParentId = getRSParentId(); if (rsParentId != -1) { @@ -198,6 +200,8 @@ public abstract class RSWidgetMixin implements RSWidget @Override public boolean isHidden() { + assert client.isClientThread(); + if (isSelfHidden()) { return true; @@ -359,6 +363,8 @@ public abstract class RSWidgetMixin implements RSWidget @Override public Widget[] getNestedChildren() { + assert client.isClientThread(); + if (getRSParentId() == getId()) { // This is a dynamic widget, so it can't have nested children @@ -494,6 +500,8 @@ public abstract class RSWidgetMixin implements RSWidget @Override public Widget createChild(int index, int type) { + assert client.isClientThread(); + RSWidget w = client.createWidget(); w.setType(type); w.setParentId(getId()); @@ -537,6 +545,8 @@ public abstract class RSWidgetMixin implements RSWidget @Override public void revalidate() { + assert client.isClientThread(); + client.revalidateWidget(this); } @@ -544,6 +554,8 @@ public abstract class RSWidgetMixin implements RSWidget @Override public void revalidateScroll() { + assert client.isClientThread(); + client.revalidateWidget(this); client.revalidateWidgetScroll(client.getWidgets()[TO_GROUP(this.getId())], this, false); } From e18e063ef5051f2c501dcbcad2f8391bdfe088b9 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Mon, 1 Oct 2018 23:45:27 -0600 Subject: [PATCH 2/3] WidgetInspector: run on client thread --- .../devtools/WidgetInfoTableModel.java | 37 +++++++++-- .../plugins/devtools/WidgetInspector.java | 64 ++++++++----------- 2 files changed, 57 insertions(+), 44 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java index f9626b705a..23f524d984 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java @@ -24,24 +24,45 @@ */ package net.runelite.client.plugins.devtools; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Inject; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.function.Function; +import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import net.runelite.api.widgets.Widget; +import net.runelite.client.callback.ClientThread; public class WidgetInfoTableModel extends AbstractTableModel { + @Inject + private ClientThread clientThread; + private static final int COL_FIELD = 0; private static final int COL_VALUE = 1; private static final List fields = populateWidgetFields(); private Widget widget = null; + private Map values = null; public void setWidget(Widget w) { - this.widget = w; - fireTableStructureChanged(); + clientThread.invoke(() -> + { + Map newValues = w == null ? null : fields.stream().collect(ImmutableMap.toImmutableMap( + Function.identity(), + i -> i.getValue(w) + )); + SwingUtilities.invokeLater(() -> + { + widget = w; + values = newValues; + fireTableStructureChanged(); + }); + }); } @Override @@ -67,11 +88,11 @@ public class WidgetInfoTableModel extends AbstractTableModel @Override public int getRowCount() { - if (widget == null) + if (values == null) { return 0; } - return fields.size(); + return values.size(); } @Override @@ -83,7 +104,7 @@ public class WidgetInfoTableModel extends AbstractTableModel case COL_FIELD: return field.getName(); case COL_VALUE: - return field.getValue(widget); + return values.get(field); default: return null; } @@ -104,7 +125,11 @@ public class WidgetInfoTableModel extends AbstractTableModel public void setValueAt(Object value, int rowIndex, int columnIndex) { WidgetField field = fields.get(rowIndex); - field.setValue(widget, value); + clientThread.invoke(() -> + { + field.setValue(widget, value); + setWidget(widget); + }); } private static List populateWidgetFields() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspector.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspector.java index d5de3a82c4..7921942948 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspector.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspector.java @@ -36,7 +36,6 @@ import java.awt.event.WindowEvent; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ExecutionException; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; @@ -45,7 +44,7 @@ import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTree; -import javax.swing.SwingWorker; +import javax.swing.SwingUtilities; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; 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.WidgetInfo; import net.runelite.api.widgets.WidgetItem; +import net.runelite.client.callback.ClientThread; import net.runelite.client.ui.ClientUI; @Slf4j class WidgetInspector extends JFrame { private final Client client; + private final ClientThread clientThread; private final DevToolsPlugin plugin; private final DevToolsConfig config; @@ -70,10 +71,11 @@ class WidgetInspector extends JFrame private static final Map widgetIdMap = new HashMap<>(); @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.client = client; + this.clientThread = clientThread; this.infoTableModel = infoTableModel; this.config = config; @@ -157,45 +159,31 @@ class WidgetInspector extends JFrame private void refreshWidgets() { - new SwingWorker() + clientThread.invokeLater(() -> { - @Override - protected DefaultMutableTreeNode doInBackground() throws Exception - { - Widget[] rootWidgets = client.getWidgetRoots(); - 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.itemIndex = -1; - - for (Widget widget : rootWidgets) - { - 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(); + refreshInfo(); + widgetTree.setModel(new DefaultTreeModel(root)); + }); + }); } private DefaultMutableTreeNode addWidget(String type, Widget widget) From 335b44852cacc36d373e47912d746971d6c954c7 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Tue, 2 Oct 2018 01:03:34 -0600 Subject: [PATCH 3/3] runelite-client: Make Widget::isHidden only run on client thread --- .../client/plugins/bankvalue/BankValuePlugin.java | 6 +++++- .../client/plugins/motherlode/MotherlodePlugin.java | 13 ++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/bankvalue/BankValuePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/bankvalue/BankValuePlugin.java index 277a3cf204..5f1bde8251 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/bankvalue/BankValuePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/bankvalue/BankValuePlugin.java @@ -32,6 +32,7 @@ import net.runelite.api.Client; import net.runelite.api.events.GameTick; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -46,6 +47,9 @@ public class BankValuePlugin extends Plugin @Inject private Client client; + @Inject + private ClientThread clientThread; + @Inject private BankCalculation bankCalculation; @@ -61,7 +65,7 @@ public class BankValuePlugin extends Plugin @Override protected void shutDown() { - bankTitle.reset(); + clientThread.invokeLater(bankTitle::reset); } @Subscribe diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodePlugin.java index 5e14d64cca..402e3d0c1a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodePlugin.java @@ -66,6 +66,7 @@ import net.runelite.api.events.WallObjectDespawned; import net.runelite.api.events.WallObjectSpawned; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -112,6 +113,9 @@ public class MotherlodePlugin extends Plugin @Inject private Client client; + @Inject + private ClientThread clientThread; + @Getter(AccessLevel.PACKAGE) private boolean inMlm; @@ -165,10 +169,13 @@ public class MotherlodePlugin extends Plugin 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()