From 0ec8d7615f11d3e8d3dd4fe8d2b711a926f3a4cb Mon Sep 17 00:00:00 2001 From: Max Weber Date: Thu, 15 Mar 2018 16:07:13 -0600 Subject: [PATCH] runelite-client: Add ClientThread to aid in synchronizing with the client --- .../java/net/runelite/api/GameEngine.java | 4 + .../client/callback/ClientThread.java | 75 +++++++++++++++++++ .../net/runelite/client/callback/Hooks.java | 3 + .../net/runelite/mixins/RSClientMixin.java | 2 +- .../runelite/mixins/RSGameEngineMixin.java | 62 +++++++++++++++ .../net/runelite/rs/api/RSGameEngine.java | 3 +- 6 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java create mode 100644 runelite-mixins/src/main/java/net/runelite/mixins/RSGameEngineMixin.java diff --git a/runelite-api/src/main/java/net/runelite/api/GameEngine.java b/runelite-api/src/main/java/net/runelite/api/GameEngine.java index a1c23d9b4f..c787ca07e8 100644 --- a/runelite-api/src/main/java/net/runelite/api/GameEngine.java +++ b/runelite-api/src/main/java/net/runelite/api/GameEngine.java @@ -29,4 +29,8 @@ import java.awt.Canvas; public interface GameEngine { Canvas getCanvas(); + + Thread getClientThread(); + + boolean isClientThread(); } diff --git a/runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java b/runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java new file mode 100644 index 0000000000..08ae4011b5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018 Abex + * 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.callback; + +import com.google.inject.Inject; +import java.util.Iterator; +import java.util.concurrent.ConcurrentLinkedQueue; +import javax.inject.Singleton; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; + +@Singleton +@Slf4j +public class ClientThread +{ + private ConcurrentLinkedQueue invokes = new ConcurrentLinkedQueue<>(); + + @Inject + private Client client; + + public void invokeLater(Runnable r) + { + if (client.isClientThread()) + { + r.run(); + return; + } + invokes.add(r); + } + + void invoke() + { + assert client.isClientThread(); + Iterator ir = invokes.iterator(); + for (; ir.hasNext(); ) + { + Runnable r = ir.next(); + ir.remove(); + try + { + r.run(); + } + catch (ThreadDeath d) + { + throw d; + } + catch (Throwable e) + { + log.warn("Exception in invokeLater", e); + } + } + } +} 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 f1e669caaf..9902b48439 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 @@ -85,6 +85,7 @@ public class Hooks private static final OverlayRenderer renderer = injector.getInstance(OverlayRenderer.class); private static final MouseManager mouseManager = injector.getInstance(MouseManager.class); 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 Dimension lastStretchedDimensions; @@ -95,6 +96,8 @@ public class Hooks public static void clientMainLoop(Client client, boolean arg1) { + clientThread.invoke(); + long now = System.currentTimeMillis(); if (now - lastCheck < CHECK) 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 5fedaebdec..c4c4d94eac 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -55,8 +55,8 @@ import net.runelite.api.SpritePixels; import net.runelite.api.Varbits; import net.runelite.api.WidgetNode; import net.runelite.api.coords.LocalPoint; -import net.runelite.api.events.DraggingWidgetChanged; import net.runelite.api.events.BoostedLevelChanged; +import net.runelite.api.events.DraggingWidgetChanged; import net.runelite.api.events.ExperienceChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GrandExchangeOfferChanged; diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSGameEngineMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSGameEngineMixin.java new file mode 100644 index 0000000000..5d9d2259cb --- /dev/null +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSGameEngineMixin.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Abex + * 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.mixins; + +import net.runelite.api.mixins.Copy; +import net.runelite.api.mixins.Inject; +import net.runelite.api.mixins.Mixin; +import net.runelite.api.mixins.Replace; +import net.runelite.rs.api.RSGameEngine; + +@Mixin(RSGameEngine.class) +public abstract class RSGameEngineMixin implements RSGameEngine +{ + @Inject + private Thread thread; + + @Inject + @Override + public Thread getClientThread() + { + return thread; + } + + @Inject + @Override + public boolean isClientThread() + { + return thread == Thread.currentThread(); + } + + @Copy("run") + public abstract void rs$run(); + + @Replace("run") + public void rl$run() + { + thread = Thread.currentThread(); + rs$run(); + } +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSGameEngine.java b/runescape-api/src/main/java/net/runelite/rs/api/RSGameEngine.java index e1f496943f..8c0024c691 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSGameEngine.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSGameEngine.java @@ -25,10 +25,11 @@ package net.runelite.rs.api; import java.awt.Canvas; +import net.runelite.api.GameEngine; import net.runelite.api.KeyFocusListener; import net.runelite.mapping.Import; -public interface RSGameEngine extends KeyFocusListener +public interface RSGameEngine extends GameEngine, KeyFocusListener { @Import("canvas") Canvas getCanvas();