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); }