From 34e37dcc575e4f867c4d99a2b5c00ce1bffabdc1 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 14 Dec 2020 21:01:46 -0500 Subject: [PATCH] Add interface and layer draw hooks for overlays This allows overlays to request draw after any interface or layer. This allows removal of the ABOVE_MAP layer which can now just be replaced with requesting draw after the map interface. This also fixes item overlays from drawing over top of the map by now drawing the item overlay immediately after the interface and/or layer the item is on is drawn. For backwards compatability, ABOVE_WIDGETS is kept as a layer, but internally just requests draw after the 3 TLIs. Due to overlays defaulting to the UNDER_WIDGETS layer, a new layer MANUAL has been added, which is intended for use when requesting draw after specific interfaces or layers, so that the overlay is otherwise not drawn a second time due to being UNDER_WIDGETS. --- .../net/runelite/api/hooks/Callbacks.java | 17 +++- .../net/runelite/client/callback/Hooks.java | 63 +++++++-------- .../devtools/WidgetInspectorOverlay.java | 2 + .../devtools/WorldMapLocationOverlay.java | 4 +- .../devtools/WorldMapRegionOverlay.java | 4 +- .../ScreenMarkerCreationOverlay.java | 2 +- .../runelite/client/ui/overlay/Overlay.java | 12 +++ .../client/ui/overlay/OverlayLayer.java | 11 +-- .../client/ui/overlay/OverlayManager.java | 78 +++++++++++++------ .../client/ui/overlay/OverlayRenderer.java | 65 ++++++++++------ .../client/ui/overlay/WidgetItemOverlay.java | 39 +++------- .../client/ui/overlay/WidgetOverlay.java | 2 + .../ui/overlay/tooltip/TooltipOverlay.java | 5 +- .../ui/overlay/worldmap/WorldMapOverlay.java | 4 +- 14 files changed, 186 insertions(+), 122 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/hooks/Callbacks.java b/runelite-api/src/main/java/net/runelite/api/hooks/Callbacks.java index 07d00487bc..c03adf5d09 100644 --- a/runelite-api/src/main/java/net/runelite/api/hooks/Callbacks.java +++ b/runelite-api/src/main/java/net/runelite/api/hooks/Callbacks.java @@ -28,7 +28,9 @@ import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; +import java.util.List; import net.runelite.api.MainBufferProvider; +import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetItem; /** @@ -70,8 +72,6 @@ public interface Callbacks */ void drawAboveOverheads(); - void drawAfterWidgets(); - /** * Client top-most draw method, rendering over top of most of game interfaces. * @@ -83,9 +83,18 @@ public interface Callbacks void draw(MainBufferProvider mainBufferProvider, Graphics graphics, int x, int y); /** - * Called before the client will render an item widget. + * Called after an interface has been drawn + * @param interfaceId the interface id + * @param widgetItems Widget items within the interface */ - void drawItem(int itemId, WidgetItem widgetItem); + void drawInterface(int interfaceId, List widgetItems); + + /** + * Called after a widget layer has been drawn + * @param layer The layer + * @param widgetItems Widget items within the layer + */ + void drawLayer(Widget layer, List widgetItems); /** * Mouse pressed event. If this event will be consumed it will not be propagated further to client. diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java index 6c725bab94..dd16869ee5 100644 --- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java +++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java @@ -36,12 +36,12 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.MainBufferProvider; -import net.runelite.api.NullItemID; import net.runelite.api.RenderOverview; import net.runelite.api.Skill; import net.runelite.api.WorldMapManager; @@ -64,7 +64,6 @@ import net.runelite.client.task.Scheduler; import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.DrawManager; import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.OverlayRenderer; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.util.DeferredEventBus; @@ -90,9 +89,6 @@ public class Hooks implements Callbacks @Inject private OverlayRenderer renderer; - @Inject - private OverlayManager overlayManager; - @Inject private EventBus eventBus; @@ -328,7 +324,7 @@ public class Hooks implements Callbacks try { - renderer.render(graphics2d, OverlayLayer.ALWAYS_ON_TOP); + renderer.renderOverlayLayer(graphics2d, OverlayLayer.ALWAYS_ON_TOP); } catch (Exception ex) { @@ -423,7 +419,7 @@ public class Hooks implements Callbacks try { - renderer.render(graphics2d, OverlayLayer.ABOVE_SCENE); + renderer.renderOverlayLayer(graphics2d, OverlayLayer.ABOVE_SCENE); } catch (Exception ex) { @@ -439,7 +435,7 @@ public class Hooks implements Callbacks try { - renderer.render(graphics2d, OverlayLayer.UNDER_WIDGETS); + renderer.renderOverlayLayer(graphics2d, OverlayLayer.UNDER_WIDGETS); } catch (Exception ex) { @@ -447,27 +443,6 @@ public class Hooks implements Callbacks } } - @Override - public void drawAfterWidgets() - { - MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider(); - Graphics2D graphics2d = getGraphics(bufferProvider); - - try - { - renderer.render(graphics2d, OverlayLayer.ABOVE_MAP); - renderer.render(graphics2d, OverlayLayer.ABOVE_WIDGETS); - } - catch (Exception ex) - { - log.warn("Error during overlay rendering", ex); - } - - // WidgetItemOverlays render at ABOVE_WIDGETS, reset widget item - // list for next frame. - overlayManager.getWidgetItems().clear(); - } - @Subscribe public void onGameStateChanged(GameStateChanged gameStateChanged) { @@ -505,12 +480,34 @@ public class Hooks implements Callbacks } @Override - public void drawItem(int itemId, WidgetItem widgetItem) + public void drawInterface(int interfaceId, List widgetItems) { - // Empty bank item - if (widgetItem.getId() != NullItemID.NULL_6512) + MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider(); + Graphics2D graphics2d = getGraphics(bufferProvider); + + try { - overlayManager.getWidgetItems().add(widgetItem); + renderer.renderAfterInterface(graphics2d, interfaceId, widgetItems); + } + catch (Exception ex) + { + log.warn("Error during overlay rendering", ex); + } + } + + @Override + public void drawLayer(Widget layer, List widgetItems) + { + MainBufferProvider bufferProvider = (MainBufferProvider) client.getBufferProvider(); + Graphics2D graphics2d = getGraphics(bufferProvider); + + try + { + renderer.renderAfterLayer(graphics2d, layer, widgetItems); + } + catch (Exception ex) + { + log.warn("Error during overlay rendering", ex); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspectorOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspectorOverlay.java index c0ceab94a8..27b83f0f2a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspectorOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInspectorOverlay.java @@ -37,6 +37,7 @@ import javax.inject.Singleton; import net.runelite.api.Client; import net.runelite.api.MenuEntry; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetItem; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -61,6 +62,7 @@ public class WidgetInspectorOverlay extends Overlay setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_WIDGETS); setPriority(OverlayPriority.HIGHEST); + drawAfterInterface(WidgetID.FULLSCREEN_MAP_GROUP_ID); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java index c0ee198533..fbeedbedfe 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java @@ -35,6 +35,7 @@ import net.runelite.api.Point; import net.runelite.api.RenderOverview; import net.runelite.api.coords.WorldPoint; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -56,7 +57,8 @@ public class WorldMapLocationOverlay extends Overlay this.plugin = plugin; setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGHEST); - setLayer(OverlayLayer.ABOVE_MAP); + setLayer(OverlayLayer.MANUAL); + drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java index 1e136267b8..8bfbf54398 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java @@ -35,6 +35,7 @@ import net.runelite.api.Client; import net.runelite.api.Point; import net.runelite.api.RenderOverview; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -56,7 +57,8 @@ class WorldMapRegionOverlay extends Overlay { setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGH); - setLayer(OverlayLayer.ABOVE_MAP); + setLayer(OverlayLayer.MANUAL); + drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID); this.client = client; this.plugin = plugin; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java index ed60dd119a..98b2c9a73b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java @@ -43,7 +43,7 @@ class ScreenMarkerCreationOverlay extends Overlay { this.plugin = plugin; setPosition(OverlayPosition.DETACHED); - setLayer(OverlayLayer.ALWAYS_ON_TOP); + setLayer(OverlayLayer.ABOVE_WIDGETS); setPriority(OverlayPriority.HIGH); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java index 405fe28080..151c5eae97 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java @@ -33,6 +33,7 @@ import javax.annotation.Nullable; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; +import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.plugins.Plugin; import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity; @@ -49,6 +50,7 @@ public abstract class Overlay implements LayoutableRenderableEntity private OverlayPosition position = OverlayPosition.TOP_LEFT; private OverlayPriority priority = OverlayPriority.NONE; private OverlayLayer layer = OverlayLayer.UNDER_WIDGETS; + private final List drawHooks = new ArrayList<>(); private final List menuEntries = new ArrayList<>(); private boolean resizable; private int minimumSize = 32; @@ -81,6 +83,16 @@ public abstract class Overlay implements LayoutableRenderableEntity return this.getClass().getSimpleName(); } + protected void drawAfterInterface(int interfaceId) + { + drawHooks.add(interfaceId << 16 | 0xffff); + } + + protected void drawAfterLayer(WidgetInfo layer) + { + drawHooks.add(layer.getId()); + } + public void onMouseOver() { } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayLayer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayLayer.java index ac75932ad6..35b72220f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayLayer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayLayer.java @@ -26,6 +26,12 @@ package net.runelite.client.ui.overlay; public enum OverlayLayer { + /** + * Overlay is not rendered. Requires using drawAfterInterface() or drawAfterLayer() + * to specify when to draw. + */ + MANUAL, + /** * Render right above the scene (that contains actors and the surface) */ @@ -45,9 +51,4 @@ public enum OverlayLayer * Render overlay above all game elements */ ALWAYS_ON_TOP, - - /** - * Render over the map, even when it's fullscreen - */ - ABOVE_MAP, } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java index 9bc2b57769..6e3c770b37 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java @@ -25,21 +25,24 @@ package net.runelite.client.ui.overlay; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ArrayListMultimap; import java.awt.Dimension; import java.awt.Point; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.EnumMap; import java.util.List; -import java.util.Map; import java.util.function.Predicate; import javax.inject.Inject; import javax.inject.Singleton; import lombok.AccessLevel; import lombok.Getter; +import lombok.Setter; import net.runelite.api.MenuAction; import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetItem; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigManager; @@ -66,13 +69,8 @@ public class OverlayManager @VisibleForTesting static final Comparator OVERLAY_COMPARATOR = (a, b) -> { - final OverlayPosition aPos = a.getPreferredPosition() != null - ? a.getPreferredPosition() - : a.getPosition(); - - final OverlayPosition bPos = b.getPreferredPosition() != null - ? b.getPreferredPosition() - : b.getPosition(); + final OverlayPosition aPos = MoreObjects.firstNonNull(a.getPreferredPosition(), a.getPosition()); + final OverlayPosition bPos = MoreObjects.firstNonNull(b.getPreferredPosition(), b.getPosition()); if (aPos != bPos) { @@ -84,7 +82,7 @@ public class OverlayManager // For dynamic overlays, higher priority means to // draw *later* so it is on top. // For non-dynamic overlays, higher priority means - // draw *first* so that they are closer to their + // draw *earlier* so that they are closer to their // defined position. return aPos == OverlayPosition.DYNAMIC ? a.getPriority().compareTo(b.getPriority()) @@ -98,9 +96,16 @@ public class OverlayManager @Getter(AccessLevel.PACKAGE) private final List overlays = new ArrayList<>(); @Getter - private final List widgetItems = new ArrayList<>(); + @Setter + private Collection widgetItems = Collections.emptyList(); - private final Map> overlayLayers = new EnumMap<>(OverlayLayer.class); + /** + * Valid keys are: + * OverlayLayer ABOVE_SCENE, UNDER_WIDGETS, and ALWAYS_ON_TOP + * A component id that is a layer + * An interface id << 16 | 0xffff + */ + private ArrayListMultimap overlayMap = ArrayListMultimap.create(); private final ConfigManager configManager; private final EventBus eventBus; @@ -164,9 +169,19 @@ public class OverlayManager * @param layer the layer * @return An immutable list of all of the overlays on that layer */ - synchronized List getLayer(OverlayLayer layer) + Collection getLayer(OverlayLayer layer) { - return overlayLayers.get(layer); + return Collections.unmodifiableCollection(overlayMap.get(layer)); + } + + Collection getForInterface(int interfaceId) + { + return Collections.unmodifiableCollection(overlayMap.get(interfaceId << 16 | 0xffff)); + } + + Collection getForLayer(int layerId) + { + return Collections.unmodifiableCollection(overlayMap.get(layerId)); } /** @@ -282,11 +297,7 @@ public class OverlayManager synchronized void rebuildOverlayLayers() { - for (OverlayLayer l : OverlayLayer.values()) - { - overlayLayers.put(l, new ArrayList<>()); - } - + ArrayListMultimap overlayMap = ArrayListMultimap.create(); for (final Overlay overlay : overlays) { OverlayLayer layer = overlay.getLayer(); @@ -301,14 +312,33 @@ public class OverlayManager } } - overlayLayers.get(layer).add(overlay); + switch (layer) + { + case ABOVE_SCENE: + case UNDER_WIDGETS: + case ALWAYS_ON_TOP: + overlayMap.put(layer, overlay); + break; + case ABOVE_WIDGETS: + // draw after each of the top level interfaces + overlayMap.put(WidgetID.FIXED_VIEWPORT_GROUP_ID << 16 | 0xffff, overlay); + overlayMap.put(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID << 16 | 0xffff, overlay); + overlayMap.put(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID << 16 | 0xffff, overlay); + break; + } + + for (int drawHook : overlay.getDrawHooks()) + { + overlayMap.put(drawHook, overlay); + } } - overlayLayers.forEach((layer, value) -> + for (Object key : overlayMap.keys()) { - value.sort(OVERLAY_COMPARATOR); - overlayLayers.put(layer, Collections.unmodifiableList(value)); - }); + overlayMap.get(key).sort(OVERLAY_COMPARATOR); + } + + this.overlayMap = overlayMap; } private void loadOverlay(final Overlay overlay) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java index 7ac97fe42a..e1666d8b14 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java @@ -39,6 +39,8 @@ import java.awt.Stroke; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; +import java.util.Collection; +import java.util.Collections; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -54,6 +56,7 @@ import net.runelite.api.events.ClientTick; import net.runelite.api.events.FocusChanged; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetItem; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.input.KeyListener; @@ -101,7 +104,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener private Rectangle chatboxBounds; private boolean chatboxHidden; private boolean isResizeable; - private OverlayBounds snapCorners; + private OverlayBounds emptySnapCorners, snapCorners; @Inject private OverlayRenderer( @@ -167,35 +170,51 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener public void onBeforeRender(BeforeRender event) { menuEntries = null; + + if (client.getGameState() == GameState.LOGGED_IN) + { + + if (shouldInvalidateBounds()) + { + emptySnapCorners = buildSnapCorners(); + } + + // Create copy of snap corners because overlays will modify them + snapCorners = new OverlayBounds(emptySnapCorners); + } } - public void render(Graphics2D graphics, final OverlayLayer layer) + public void renderOverlayLayer(Graphics2D graphics, final OverlayLayer layer) { - if (layer != OverlayLayer.ABOVE_MAP - && client.getWidget(WidgetInfo.FULLSCREEN_MAP_ROOT) != null - && !client.getWidget(WidgetInfo.FULLSCREEN_MAP_ROOT).isHidden()) - { - return; - } + final Collection overlays = overlayManager.getLayer(layer); + renderOverlays(graphics, overlays, layer); + } - final List overlays = overlayManager.getLayer(layer); + public void renderAfterInterface(Graphics2D graphics, int interfaceId, Collection widgetItems) + { + Collection overlays = overlayManager.getForInterface(interfaceId); + overlayManager.setWidgetItems(widgetItems); + renderOverlays(graphics, overlays, OverlayLayer.ABOVE_WIDGETS); + overlayManager.setWidgetItems(Collections.emptyList()); + } + public void renderAfterLayer(Graphics2D graphics, Widget layer, Collection widgetItems) + { + Collection overlays = overlayManager.getForLayer(layer.getId()); + overlayManager.setWidgetItems(widgetItems); + renderOverlays(graphics, overlays, OverlayLayer.ABOVE_WIDGETS); + overlayManager.setWidgetItems(Collections.emptyList()); + } + + private void renderOverlays(Graphics2D graphics, Collection overlays, OverlayLayer layer) + { if (overlays == null || overlays.isEmpty() - || client.getGameState() != GameState.LOGGED_IN - || client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN) != null - || getViewportLayer() == null) + || client.getGameState() != GameState.LOGGED_IN) { return; } - if (shouldInvalidateBounds()) - { - snapCorners = buildSnapCorners(); - } - - // Create copy of snap corners because overlays will modify them - OverlayBounds snapCorners = new OverlayBounds(this.snapCorners); OverlayUtil.setGraphicProperties(graphics); // Draw snap corners @@ -629,7 +648,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener // Check if the overlay is over a snapcorner and move it if so, unless it is a detached overlay if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode) { - final OverlayBounds snapCorners = this.snapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height); + final OverlayBounds snapCorners = this.emptySnapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height); for (Rectangle snapCorner : snapCorners.getBounds()) { @@ -795,11 +814,13 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener changed = true; } - final boolean viewportChanged = !getViewportLayer().getBounds().equals(viewportBounds); + Widget viewportWidget = getViewportLayer(); + Rectangle viewport = viewportWidget != null ? viewportWidget.getBounds() : new Rectangle(); + final boolean viewportChanged = !viewport.equals(viewportBounds); if (viewportChanged) { - viewportBounds = getViewportLayer().getBounds(); + viewportBounds = viewport; changed = true; } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java index 5d1e404575..066c52402a 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetItemOverlay.java @@ -28,45 +28,36 @@ import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.Collection; import lombok.AccessLevel; import lombok.Setter; import net.runelite.api.widgets.Widget; -import static net.runelite.api.widgets.WidgetID.BANK_GROUP_ID; import static net.runelite.api.widgets.WidgetID.BANK_INVENTORY_GROUP_ID; import static net.runelite.api.widgets.WidgetID.DEPOSIT_BOX_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_OTHER_GROUP_ID; import static net.runelite.api.widgets.WidgetID.EQUIPMENT_GROUP_ID; import static net.runelite.api.widgets.WidgetID.EQUIPMENT_INVENTORY_GROUP_ID; import static net.runelite.api.widgets.WidgetID.GRAND_EXCHANGE_INVENTORY_GROUP_ID; import static net.runelite.api.widgets.WidgetID.GUIDE_PRICES_INVENTORY_GROUP_ID; import static net.runelite.api.widgets.WidgetID.INVENTORY_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_INVENTORY_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_SCREEN_GROUP_ID; import static net.runelite.api.widgets.WidgetID.SEED_VAULT_INVENTORY_GROUP_ID; import static net.runelite.api.widgets.WidgetID.SHOP_INVENTORY_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.DUEL_INVENTORY_OTHER_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_SCREEN_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.PLAYER_TRADE_INVENTORY_GROUP_ID; -import static net.runelite.api.widgets.WidgetInfo.BANK_CONTENT_CONTAINER; -import static net.runelite.api.widgets.WidgetInfo.BANK_TAB_CONTAINER; -import static net.runelite.api.widgets.WidgetInfo.TO_GROUP; +import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetItem; public abstract class WidgetItemOverlay extends Overlay { @Setter(AccessLevel.PACKAGE) private OverlayManager overlayManager; - /** - * Interfaces to draw overlay over. - */ - private final Set interfaceGroups = new HashSet<>(); protected WidgetItemOverlay() { super.setPosition(OverlayPosition.DYNAMIC); super.setPriority(OverlayPriority.LOW); - super.setLayer(OverlayLayer.ABOVE_WIDGETS); + super.setLayer(OverlayLayer.MANUAL); } public abstract void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem); @@ -74,22 +65,12 @@ public abstract class WidgetItemOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - final List widgetItems = overlayManager.getWidgetItems(); + final Collection widgetItems = overlayManager.getWidgetItems(); final Rectangle originalClipBounds = graphics.getClipBounds(); Widget curClipParent = null; for (WidgetItem widgetItem : widgetItems) { Widget widget = widgetItem.getWidget(); - int interfaceGroup = TO_GROUP(widget.getId()); - - // Don't draw if this widget isn't one of the allowed nor in tag tab/item tab - if (!interfaceGroups.contains(interfaceGroup) || - (interfaceGroup == BANK_GROUP_ID - && (widget.getParentId() == BANK_CONTENT_CONTAINER.getId() || widget.getParentId() == BANK_TAB_CONTAINER.getId()))) - { - continue; - } - Widget parent = widget.getParent(); Rectangle parentBounds = parent.getBounds(); Rectangle itemCanvasBounds = widgetItem.getCanvasBounds(); @@ -151,7 +132,7 @@ public abstract class WidgetItemOverlay extends Overlay protected void showOnBank() { - showOnInterfaces(BANK_GROUP_ID); + drawAfterLayer(WidgetInfo.BANK_ITEM_CONTAINER); } protected void showOnEquipment() @@ -161,7 +142,7 @@ public abstract class WidgetItemOverlay extends Overlay protected void showOnInterfaces(int... ids) { - Arrays.stream(ids).forEach(interfaceGroups::add); + Arrays.stream(ids).forEach(this::drawAfterInterface); } // Don't allow setting position, priority, or layer diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java index d5f57d6590..c1c1028375 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java @@ -80,6 +80,8 @@ public class WidgetOverlay extends Overlay setPriority(OverlayPriority.HIGHEST); setLayer(OverlayLayer.UNDER_WIDGETS); setPosition(overlayPosition); + // It's almost possible to drawAfterInterface(widgetInfo.getGroupId()) here, but that fires + // *after* the native components are drawn, which is too late. } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java index 1f68a348f4..002af12c34 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java @@ -32,6 +32,7 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.Client; +import net.runelite.api.widgets.WidgetID; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.config.TooltipPositionType; import net.runelite.client.ui.overlay.Overlay; @@ -59,7 +60,9 @@ public class TooltipOverlay extends Overlay this.runeLiteConfig = runeLiteConfig; setPosition(OverlayPosition.TOOLTIP); setPriority(OverlayPriority.HIGHEST); - setLayer(OverlayLayer.ALWAYS_ON_TOP); + setLayer(OverlayLayer.ABOVE_WIDGETS); + // additionally allow tooltips above the world map + drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java index 7e301c8e61..8b2fc1d187 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java @@ -39,6 +39,7 @@ import net.runelite.api.Point; import net.runelite.api.RenderOverview; import net.runelite.api.coords.WorldPoint; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.input.MouseManager; import net.runelite.client.ui.FontManager; @@ -73,7 +74,8 @@ public class WorldMapOverlay extends Overlay this.worldMapPointManager = worldMapPointManager; setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGHEST); - setLayer(OverlayLayer.ABOVE_MAP); + setLayer(OverlayLayer.MANUAL); + drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID); mouseManager.registerMouseListener(worldMapOverlayMouseListener); }