diff --git a/runelite-api/src/main/java/net/runelite/api/Varbits.java b/runelite-api/src/main/java/net/runelite/api/Varbits.java index d50c1fbc6b..57be511e59 100644 --- a/runelite-api/src/main/java/net/runelite/api/Varbits.java +++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java @@ -307,6 +307,17 @@ public enum Varbits PERSONAL_POINTS(5422), RAID_PARTY_SIZE(5424), + /** + * Making Friends with My Arm fire pits + * + * Expected values: + * 0 = Not built + * 1 = Built + */ + FIRE_PIT_GIANT_MOLE(6532), + FIRE_PIT_LUMBRIDGE_SWAMP(6533), + FIRE_PIT_MOS_LE_HARMLESS(6544), + /** * Theatre of Blood 1=In Party, 2=Inside/Spectator, 3=Dead Spectating */ diff --git a/runelite-api/src/main/java/net/runelite/api/queries/BankItemQuery.java b/runelite-api/src/main/java/net/runelite/api/queries/BankItemQuery.java index 2153072fb8..64c79712d3 100644 --- a/runelite-api/src/main/java/net/runelite/api/queries/BankItemQuery.java +++ b/runelite-api/src/main/java/net/runelite/api/queries/BankItemQuery.java @@ -67,7 +67,7 @@ public class BankItemQuery extends WidgetItemQuery Rectangle bounds = child.getBounds(); bounds.setBounds(bounds.x - 1, bounds.y - 1, 32, 32); // Index is set to 0 because the widget's index does not correlate to the order in the bank - widgetItems.add(new WidgetItem(child.getItemId(), child.getItemQuantity(), 0, bounds, child, false)); + widgetItems.add(new WidgetItem(child.getItemId(), child.getItemQuantity(), 0, bounds, child, null)); } } return widgetItems; diff --git a/runelite-api/src/main/java/net/runelite/api/queries/DialogQuery.java b/runelite-api/src/main/java/net/runelite/api/queries/DialogQuery.java index 0b4cfb8c03..fff6f4c5f6 100644 --- a/runelite-api/src/main/java/net/runelite/api/queries/DialogQuery.java +++ b/runelite-api/src/main/java/net/runelite/api/queries/DialogQuery.java @@ -73,7 +73,7 @@ public class DialogQuery extends WidgetItemQuery // set bounds to same size as default inventory Rectangle bounds = child.getBounds(); bounds.setBounds(bounds.x - 1, bounds.y - 1, 32, 32); - widgetItems.add(new WidgetItem(child.getId(), child.getItemQuantity(), i - 1, bounds, child, false)); + widgetItems.add(new WidgetItem(child.getId(), child.getItemQuantity(), i - 1, bounds, child, null)); } } return widgetItems; diff --git a/runelite-api/src/main/java/net/runelite/api/queries/InventoryWidgetItemQuery.java b/runelite-api/src/main/java/net/runelite/api/queries/InventoryWidgetItemQuery.java index 9072dbeeda..4598439082 100644 --- a/runelite-api/src/main/java/net/runelite/api/queries/InventoryWidgetItemQuery.java +++ b/runelite-api/src/main/java/net/runelite/api/queries/InventoryWidgetItemQuery.java @@ -92,8 +92,10 @@ public class InventoryWidgetItemQuery extends WidgetItemQuery } // set bounds to same size as default inventory Rectangle bounds = child.getBounds(); - bounds.setBounds(bounds.x + dragOffsetX, bounds.y + dragOffsetY, 32, 32); - widgetItems.add(new WidgetItem(child.getItemId(), child.getItemQuantity(), i, bounds, child, isDragged)); + bounds.setBounds(bounds.x - 1, bounds.y - 1, 32, 32); + Rectangle dragBounds = child.getBounds(); + dragBounds.setBounds(bounds.x + dragOffsetX, bounds.y + dragOffsetY, 32, 32); + widgetItems.add(new WidgetItem(child.getItemId(), child.getItemQuantity(), i, bounds, child, dragBounds)); } break; } diff --git a/runelite-api/src/main/java/net/runelite/api/queries/ShopItemQuery.java b/runelite-api/src/main/java/net/runelite/api/queries/ShopItemQuery.java index a76851fe0a..a768df8928 100644 --- a/runelite-api/src/main/java/net/runelite/api/queries/ShopItemQuery.java +++ b/runelite-api/src/main/java/net/runelite/api/queries/ShopItemQuery.java @@ -60,7 +60,7 @@ public class ShopItemQuery extends WidgetItemQuery // set bounds to same size as default inventory Rectangle bounds = child.getBounds(); bounds.setBounds(bounds.x - 1, bounds.y - 1, 32, 32); - widgetItems.add(new WidgetItem(child.getItemId(), child.getItemQuantity(), i - 1, bounds, child, false)); // todo: maybe this shouldnt just be "false" + widgetItems.add(new WidgetItem(child.getItemId(), child.getItemQuantity(), i - 1, bounds, child, null)); // todo: maybe this shouldnt just be "false" } } return widgetItems; diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetItem.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetItem.java index 57b0d522f5..2ca82b204b 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetItem.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetItem.java @@ -26,6 +26,7 @@ package net.runelite.api.widgets; import net.runelite.api.Point; import java.awt.Rectangle; +import javax.annotation.Nullable; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; @@ -64,19 +65,40 @@ public class WidgetItem */ private final Widget widget; /** - * Whether or not this widget item is being dragged. + * The canvas bounds for the widget, if it is being dragged. */ - private final boolean dragging; + @Nullable + private final Rectangle draggingCanvasBounds; + + /** + * Get the area where the widget item is drawn on the canvas, accounting for drag + * @return + */ + public Rectangle getCanvasBounds() + { + return draggingCanvasBounds == null ? canvasBounds : draggingCanvasBounds; + } + + /** + * Get the area where the widget item is drawn on the canvas + * @param dragging whether the returned area should account for widget drag + * @return + */ + public Rectangle getCanvasBounds(boolean dragging) + { + return dragging ? draggingCanvasBounds : canvasBounds; + } /** * Gets the upper-left coordinate of where the widget is being drawn - * on the canvas. + * on the canvas, accounting for drag. * * @return the upper-left coordinate of where this widget is drawn */ public Point getCanvasLocation() { - return new Point((int) canvasBounds.getX(), (int) canvasBounds.getY()); + Rectangle bounds = getCanvasBounds(); + return new Point((int) bounds.getX(), (int) bounds.getY()); } } diff --git a/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java b/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java index c03e5e471e..c0cf7a656f 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java @@ -214,7 +214,7 @@ public enum ItemMapping BLACK_MASK, BLACK_MASK_I, BLACK_MASK_1, BLACK_MASK_1_I, BLACK_MASK_2, BLACK_MASK_2_I, BLACK_MASK_3, BLACK_MASK_3_I, BLACK_MASK_4, BLACK_MASK_4_I, BLACK_MASK_5, BLACK_MASK_5_I, BLACK_MASK_6, BLACK_MASK_6_I, BLACK_MASK_7, BLACK_MASK_7_I, BLACK_MASK_8, BLACK_MASK_8_I, BLACK_MASK_9, BLACK_MASK_9_I, BLACK_MASK_10_I, SLAYER_HELMET, SLAYER_HELMET_I, BLACK_SLAYER_HELMET, BLACK_SLAYER_HELMET_I, PURPLE_SLAYER_HELMET, PURPLE_SLAYER_HELMET_I, RED_SLAYER_HELMET, RED_SLAYER_HELMET_I, - GREEN_SLAYER_HELMET, GREEN_SLAYER_HELMET_I, TURQUOISE_SLAYER_HELMET, TURQUOISE_SLAYER_HELMET_I, HYDRA_SLAYER_HELMET, HYDRA_SLAYER_HELMET_I), + GREEN_SLAYER_HELMET, GREEN_SLAYER_HELMET_I, TURQUOISE_SLAYER_HELMET, TURQUOISE_SLAYER_HELMET_I, TWISTED_SLAYER_HELMET, TWISTED_SLAYER_HELMET_I, HYDRA_SLAYER_HELMET, HYDRA_SLAYER_HELMET_I), // Pharaoh's Sceptres ITEM_PHARAOHS_SCEPTRE_1(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_1), @@ -232,6 +232,7 @@ public enum ItemMapping ITEM_BOTTOMLESS_COMPOST_BUCKET(BOTTOMLESS_COMPOST_BUCKET, BOTTOMLESS_COMPOST_BUCKET_22997), ITEM_BASILISK_JAW(BASILISK_JAW, NEITIZNOT_FACEGUARD), ITEM_HELM_OF_NEITIZNOT(HELM_OF_NEITIZNOT, NEITIZNOT_FACEGUARD), + ITEM_TWISTED_HORNS(TWISTED_HORNS, TWISTED_SLAYER_HELMET, TWISTED_SLAYER_HELMET_I), // Crystal items ITEM_CRYSTAL_TOOL_SEED(CRYSTAL_TOOL_SEED, CRYSTAL_AXE, CRYSTAL_AXE_INACTIVE, CRYSTAL_HARPOON, CRYSTAL_HARPOON_INACTIVE, CRYSTAL_PICKAXE, CRYSTAL_PICKAXE_INACTIVE), diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index 5ee14960bd..d6d10e7dce 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -612,6 +612,35 @@ public class ClientUI { OSXUtil.requestFocus(); } + + // The workaround for Windows is to minimise and then un-minimise the client to bring + // it to the front because java.awt.Window#toFront doesn't work reliably. + // See https://stackoverflow.com/questions/309023/how-to-bring-a-window-to-the-front/7435722#7435722 + else if (OSType.getOSType() == OSType.Windows && !frame.isFocused()) + { + SwingUtilities.invokeLater(() -> + { + if ((frame.getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) + { + frame.setExtendedState(JFrame.ICONIFIED); + frame.setExtendedState(JFrame.MAXIMIZED_BOTH); + } + else + { + // If the client is snapped to the top and bottom edges of the screen, setExtendedState will + // will reset it so setSize and setLocation ensure that the client doesn't move or resize. + // It is done this way because Windows does not support JFrame.MAXIMIZED_VERT + int x = frame.getLocation().x; + int y = frame.getLocation().y; + int width = frame.getWidth(); + int height = frame.getHeight(); + frame.setExtendedState(JFrame.ICONIFIED); + frame.setExtendedState(JFrame.NORMAL); + frame.setLocation(x, y); + frame.setSize(width, height); + } + }); + } frame.requestFocus(); giveClientFocus(); diff --git a/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java b/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java index 5f1974c02b..42a88211e9 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/util/SwingUtil.java @@ -28,13 +28,16 @@ import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; +import java.awt.Container; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Font; import java.awt.Frame; import java.awt.Image; import java.awt.Insets; +import java.awt.SecondaryLoop; import java.awt.SystemTray; +import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -60,6 +63,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; @@ -486,4 +490,54 @@ public class SwingUtil EventQueue.invokeAndWait(r); } } + + /** + * Removes all of a component's children faster than calling removeAll() on it in many cases + */ + public static void fastRemoveAll(Container c) + { + // If we are not on the EDT this will deadlock, in addition to being totally unsafe + assert SwingUtilities.isEventDispatchThread(); + + // when a component is removed it has to be resized for some reason, but only if it's valid + // so we make sure to invalidate everything before removing it + c.invalidate(); + for (int i = 0; i < c.getComponentCount(); i++) + { + Component ic = c.getComponent(i); + + // removeAll and removeNotify are both recursive, so we have to recurse before them + if (ic instanceof Container) + { + fastRemoveAll((Container) ic); + } + + // each removeNotify needs to remove anything from the event queue that is for that widget + // this however requires taking a lock, and is moderately slow, so we just execute all of + // those events with a secondary event loop + pumpPendingEvents(); + + // call removeNotify early; this is most of the work in removeAll, and generates events that + // the next secondaryLoop will pickup + ic.removeNotify(); + } + + // Actually remove anything + c.removeAll(); + } + + /** + * Run any events currently in the event queue + */ + public static void pumpPendingEvents() + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + + if (eq.peekEvent() != null) + { + SecondaryLoop l = eq.createSecondaryLoop(); + SwingUtilities.invokeLater(l::exit); + l.enter(); + } + } } diff --git a/runelite-client/src/main/scripts/LayoutResizableStones.hash b/runelite-client/src/main/scripts/LayoutResizableStones.hash new file mode 100644 index 0000000000..1fa97dfff0 --- /dev/null +++ b/runelite-client/src/main/scripts/LayoutResizableStones.hash @@ -0,0 +1 @@ +A358C6B0EC9AF746487EA8A20507B8C03073A5C2DE16EA2FC94751957A49DA09 \ No newline at end of file diff --git a/runelite-client/src/main/scripts/LayoutResizableStones.rs2asm b/runelite-client/src/main/scripts/LayoutResizableStones.rs2asm new file mode 100644 index 0000000000..c3bec33bb8 --- /dev/null +++ b/runelite-client/src/main/scripts/LayoutResizableStones.rs2asm @@ -0,0 +1,249 @@ +.id 920 +.int_stack_count 2 +.string_stack_count 0 +.int_var_count 5 +.string_var_count 0 +; callback "forceStackStones" +; Used by the InterfaceStylesPlugin to enable it's Always stack bottom bar option +; Toggle the option when you have the bottom line top level interface on and your screen is large enough for the stones to be in a single line + iconst 0 + istore 2 + iconst 0 + istore 3 + iconst -1 + istore 4 + iload 1 + switch + 1745: LABEL129 + 1129: LABEL109 + 1130: LABEL87 + 1131: LABEL9 + jump LABEL201 +LABEL9: + iconst 10747937 + if_getwidth + iconst 33 + sub + iconst 10747937 + if_getheight + istore 3 + istore 2 + iload 0 + if_getwidth + iconst 73 + iconst 73 + iload 1 + iconst 10551326 + enum + if_getwidth + sub + iconst 429 + if_icmplt LABEL29 + iconst 0 ; should resizable stones be forced to stack + sconst "forceStackStones" ; push event name + runelite_callback ; invoke callback + iconst 0 ; if 0 is returned, continue normal layout + if_icmpeq LABEL49 +LABEL29: + iconst 0 + iload 3 + iconst 10747952 + if_getheight + add + iconst 2 + iconst 2 + iconst 73 + iconst 73 + iload 1 + iconst 10747969 + enum + if_setposition + iconst 0 + iload 3 + iconst 2 + iconst 2 + iconst 10747952 + if_setposition + jump LABEL65 +LABEL49: + iconst 0 + iload 3 + iconst 2 + iconst 2 + iconst 73 + iconst 73 + iload 1 + iconst 10747969 + enum + if_setposition + iload 2 + iconst 0 + iconst 2 + iconst 2 + iconst 10747952 + if_setposition +LABEL65: + get_varbit 4084 + iconst 1 + if_icmpeq LABEL69 + jump LABEL77 +LABEL69: + iconst 1178 + iconst 73 + iconst 73 + iload 1 + iconst 10551322 + enum + 2122 + jump LABEL84 +LABEL77: + iconst 2154 + iconst 73 + iconst 73 + iload 1 + iconst 10551322 + enum + 2122 +LABEL84: + clientclock + set_varc_int 384 + jump LABEL201 +LABEL87: + get_varbit 4084 + iconst 1 + if_icmpeq LABEL91 + jump LABEL99 +LABEL91: + iconst 1178 + iconst 73 + iconst 73 + iload 1 + iconst 10551322 + enum + 2122 + jump LABEL106 +LABEL99: + iconst 2154 + iconst 73 + iconst 73 + iload 1 + iconst 10551322 + enum + 2122 +LABEL106: + clientclock + set_varc_int 384 + jump LABEL201 +LABEL109: + invoke 3297 + iconst 1 + if_icmpeq LABEL113 + jump LABEL121 +LABEL113: + iconst 2422 + iconst 73 + iconst 73 + iload 1 + iconst 10551322 + enum + 2122 + jump LABEL128 +LABEL121: + iconst 1200 + iconst 73 + iconst 73 + iload 1 + iconst 10551322 + enum + 2122 +LABEL128: + jump LABEL201 +LABEL129: + get_varbit 6257 + iconst 1 + if_icmpeq LABEL133 + jump LABEL137 +LABEL133: + iconst 1 + iconst 39387167 + if_sethide + jump LABEL192 +LABEL137: + iconst 0 + iconst 39387167 + if_sethide + iconst 1 + iconst 39387167 + 2308 + get_varbit 6255 + switch + 1: LABEL154 + 2: LABEL146 + 3: LABEL162 + jump LABEL170 +LABEL146: + iconst 1718 + iconst 39387169 + if_setgraphic + iconst 1 + sconst "Toggle single-tap mode" + iconst 39387167 + if_setop + jump LABEL177 +LABEL154: + iconst 1717 + iconst 39387169 + if_setgraphic + iconst 1 + sconst "Toggle tap-to-drop mode" + iconst 39387167 + if_setop + jump LABEL177 +LABEL162: + iconst 1716 + iconst 39387169 + if_setgraphic + iconst 1 + sconst "Show Keyboard" + iconst 39387167 + if_setop + jump LABEL177 +LABEL170: + iconst 1715 + iconst 39387169 + if_setgraphic + iconst 1 + sconst "" + iconst 39387167 + if_setop +LABEL177: + get_varbit 6255 + iconst 3 + if_icmpne LABEL181 + jump LABEL189 +LABEL181: + get_varbit 6256 + iconst 0 + if_icmpeq LABEL185 + jump LABEL189 +LABEL185: + iconst 155 + iconst 39387169 + if_settrans + jump LABEL192 +LABEL189: + iconst 0 + iconst 39387169 + if_settrans +LABEL192: + invoke 2581 + get_varbit 6254 + invoke 633 + iconst 39387158 + if_sethide + invoke 2526 + pop_int + clientclock + set_varc_int 384 +LABEL201: + return 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 4ab9ccf557..a079fbaa53 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -1529,7 +1529,7 @@ public abstract class RSClientMixin implements RSClient { if (renderX >= minX && renderX <= maxX && renderY >= minY && renderY <= maxY) { - WidgetItem widgetItem = new WidgetItem(widget.getItemId(), widget.getItemQuantity(), -1, widget.getBounds(), widget, false); + WidgetItem widgetItem = new WidgetItem(widget.getItemId(), widget.getItemQuantity(), -1, widget.getBounds(), widget, null); callbacks.drawItem(widget.getItemId(), widgetItem); } } 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 f10da765f4..b4f7a9eefb 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java @@ -301,8 +301,9 @@ public abstract class RSWidgetMixin implements RSWidget dragOffsetY = p.getY(); } - Rectangle bounds = new Rectangle(itemX + dragOffsetX, itemY + dragOffsetY, ITEM_SLOT_SIZE, ITEM_SLOT_SIZE); - return new WidgetItem(itemId - 1, itemQuantity, index, bounds, this, isDragged); + Rectangle bounds = new Rectangle(itemX - 1, itemY - 1, ITEM_SLOT_SIZE, ITEM_SLOT_SIZE); + Rectangle draggedBounds = new Rectangle(itemX + dragOffsetX, itemY + dragOffsetY, ITEM_SLOT_SIZE, ITEM_SLOT_SIZE); + return new WidgetItem(itemId - 1, itemQuantity, index, bounds, this, draggedBounds); } @Inject