diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index cfcc2876fb..0b7a0c117c 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -50,6 +50,7 @@ import net.runelite.client.game.ItemManager; import net.runelite.client.menus.MenuManager; import net.runelite.client.plugins.PluginManager; import net.runelite.client.ui.ClientUI; +import net.runelite.client.ui.DrawManager; import net.runelite.client.ui.TitleToolbar; import net.runelite.client.ui.overlay.OverlayRenderer; import org.slf4j.LoggerFactory; @@ -89,6 +90,9 @@ public class RuneLite @Inject private OverlayRenderer overlayRenderer; + @Inject + private DrawManager drawManager; + @Inject private SessionManager sessionManager; @@ -166,6 +170,7 @@ public class RuneLite // Register event listeners eventBus.register(clientUI); eventBus.register(overlayRenderer); + eventBus.register(drawManager); eventBus.register(menuManager); eventBus.register(chatMessageManager); eventBus.register(commandManager); 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 69d5eef6c3..292cbc2826 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 @@ -69,6 +69,7 @@ import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.input.KeyManager; import net.runelite.client.input.MouseManager; import net.runelite.client.task.Scheduler; +import net.runelite.client.ui.DrawManager; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayRenderer; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; @@ -96,6 +97,7 @@ public class Hooks private static final KeyManager keyManager = injector.getInstance(KeyManager.class); private static final ClientThread clientThread = injector.getInstance(ClientThread.class); private static final GameTick tick = new GameTick(); + private static final DrawManager renderHooks = injector.getInstance(DrawManager.class); private static Dimension lastStretchedDimensions; private static BufferedImage stretchedImage; @@ -304,7 +306,7 @@ public class Hooks // Draw the image onto the game canvas graphics.drawImage(image, 0, 0, client.getCanvas()); - renderer.provideScreenshot(image); + renderHooks.processDrawComplete(image); } public static void drawRegion(Region region, int var1, int var2, int var3, int var4, int var5, int var6) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java index 9e4efb9543..779f48b9da 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java @@ -71,6 +71,7 @@ import net.runelite.api.widgets.WidgetInfo; import static net.runelite.api.widgets.WidgetInfo.TO_GROUP; import net.runelite.client.Notifier; import static net.runelite.client.RuneLite.SCREENSHOT_DIR; +import net.runelite.client.ui.DrawManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; @@ -81,7 +82,6 @@ import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.TitleToolbar; -import net.runelite.client.ui.overlay.OverlayRenderer; import net.runelite.client.util.Text; import net.runelite.http.api.RuneLiteAPI; import okhttp3.Call; @@ -131,7 +131,7 @@ public class ScreenshotPlugin extends Plugin private TitleToolbar titleToolbar; @Inject - private OverlayRenderer overlayRenderer; + private DrawManager drawManager; @Inject private ScreenshotInput inputListener; @@ -405,7 +405,7 @@ public class ScreenshotPlugin extends Plugin return; } - overlayRenderer.requestScreenshot(image -> + drawManager.requestNextFrameListener(image -> { BufferedImage screenshot = config.includeFrame() ? new BufferedImage(clientUi.getWidth(), clientUi.getHeight(), BufferedImage.TYPE_INT_ARGB) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/DrawManager.java b/runelite-client/src/main/java/net/runelite/client/ui/DrawManager.java new file mode 100644 index 0000000000..80dd22b8ea --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/DrawManager.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017, Levi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.ui; + +import java.awt.image.BufferedImage; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; +import javax.inject.Singleton; +import lombok.extern.slf4j.Slf4j; + +@Singleton +@Slf4j +public class DrawManager +{ + private final List> everyFrame = new CopyOnWriteArrayList<>(); + private final Queue> nextFrame = new ConcurrentLinkedQueue<>(); + + public void registerEveryFrameListener(Consumer everyFrameListener) + { + if (!everyFrame.contains(everyFrameListener)) + { + everyFrame.add(everyFrameListener); + } + } + + public void unregisterEveryFrameListener(Consumer everyFrameListener) + { + everyFrame.remove(everyFrameListener); + } + + public void requestNextFrameListener(Consumer nextFrameListener) + { + nextFrame.add(nextFrameListener); + } + + public void processDrawComplete(BufferedImage image) + { + for (Consumer everyFrameListener : everyFrame) + { + try + { + everyFrameListener.accept(image); + } + catch (Exception e) + { + log.error("Error in draw consumer", e); + } + } + + Consumer nextFrameListener = nextFrame.poll(); + while (nextFrameListener != null) + { + try + { + nextFrameListener.accept(image); + } + catch (Exception e) + { + log.error("Error in draw consumer", e); + } + nextFrameListener = nextFrame.poll(); + } + } +} 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 a9c1565a13..e976b2c7c9 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 @@ -33,15 +33,12 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; @@ -95,7 +92,6 @@ public class OverlayRenderer extends MouseListener implements KeyListener private final RuneLiteConfig runeLiteConfig; private final TooltipOverlay tooltipOverlay; private final List allOverlays = new CopyOnWriteArrayList<>(); - private final ConcurrentLinkedQueue> screenshotRequests = new ConcurrentLinkedQueue<>(); private final String runeliteGroupName = RuneLiteConfig.class.getAnnotation(ConfigGroup.class).keyName(); // Overlay movement variables @@ -655,25 +651,4 @@ public class OverlayRenderer extends MouseListener implements KeyListener final String locationKey = overlay.getClass().getSimpleName() + OVERLAY_CONFIG_PREFERRED_POSITION; return configManager.getConfiguration(runeliteGroupName, locationKey, OverlayPosition.class); } - - public void provideScreenshot(BufferedImage image) - { - Consumer consumer; - while ((consumer = screenshotRequests.poll()) != null) - { - try - { - consumer.accept(image); - } - catch (Exception ex) - { - log.warn("error in screenshot callback", ex); - } - } - } - - public void requestScreenshot(Consumer consumer) - { - screenshotRequests.add(consumer); - } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java index 9aae5fc48e..2c7699e9e4 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java @@ -43,7 +43,7 @@ import static net.runelite.api.widgets.WidgetInfo.PACK; import net.runelite.client.Notifier; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.ui.ClientUI; -import net.runelite.client.ui.overlay.OverlayRenderer; +import net.runelite.client.ui.DrawManager; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; @@ -83,7 +83,7 @@ public class ScreenshotPluginTest @Mock @Bind - private OverlayRenderer overlayRenderer; + DrawManager drawManager; @Mock @Bind @@ -146,7 +146,7 @@ public class ScreenshotPluginTest event.setWidget(widget); screenshotPlugin.hideWidgets(event); - verify(overlayRenderer).requestScreenshot(Matchers.any(Consumer.class)); + verify(drawManager).requestNextFrameListener(Matchers.any(Consumer.class)); } @Test @@ -166,7 +166,7 @@ public class ScreenshotPluginTest event.setWidget(widget); screenshotPlugin.hideWidgets(event); - verify(overlayRenderer).requestScreenshot(Matchers.any(Consumer.class)); + verify(drawManager).requestNextFrameListener(Matchers.any(Consumer.class)); } @Test @@ -186,7 +186,7 @@ public class ScreenshotPluginTest event.setWidget(widget); screenshotPlugin.hideWidgets(event); - verify(overlayRenderer).requestScreenshot(Matchers.any(Consumer.class)); + verify(drawManager).requestNextFrameListener(Matchers.any(Consumer.class)); } @Test @@ -206,6 +206,6 @@ public class ScreenshotPluginTest event.setWidget(widget); screenshotPlugin.hideWidgets(event); - verify(overlayRenderer).requestScreenshot(Matchers.any(Consumer.class)); + verify(drawManager).requestNextFrameListener(Matchers.any(Consumer.class)); } }