diff --git a/.gitignore b/.gitignore index db74f6f1..b2a7d128 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,9 @@ build/ .gradle/ OsrsBot.jar .idea/ + +target/* +.clj-kondo/* +.lsp/* + +output/* diff --git a/partial-patch.sh b/partial-patch.sh new file mode 100644 index 00000000..db24689d --- /dev/null +++ b/partial-patch.sh @@ -0,0 +1,31 @@ +target_file="~/Code/OsrsBot/src/main/java/net/runelite/rsb/wrappers/client_wrapper/RSClient.java" +lein run 2>&1 | while read -r line; do + if echo "$line" | grep -q "return type void is not compatible with"; then + type=$(echo "$line" | awk '{print $9}') + fi + if echo "$line" | grep -q "RSClient is not abstract and does not override abstract method"; then + method=$(echo "$line" | awk '{print $13}') + echo "public void $method { $method; }" + sed -i '$ d' "$target_file" + echo "public void $method { $method; }" >> "$target_file" + echo "}" >> "$target_file" + fi +done + +lein run 2>&1 | while read -r line; do + if echo "$line" | grep -q "return type void is not compatible with"; then + type=$(echo "$line" | awk '{print $8}') + echo "public $type $method { $method; }" + sed -i '$ d' "$target_file" + sed -i '$ d' "$target_file" + echo "public $type $method { return $method; }" >> "$target_file" + echo "}" >> "$target_file" + fi + if echo "$line" | grep -q "RSClient is not abstract and does not override abstract method"; then + method=$(echo "$line" | awk '{print $13}') + + fi +done + + + diff --git a/project.clj b/project.clj new file mode 100644 index 00000000..4d4612b5 --- /dev/null +++ b/project.clj @@ -0,0 +1,24 @@ +(defn get-runelite-version [] + ()) + +(defproject OSRSB "0.0.1" + :description "A revised bot client on RuneLite (for now)" + :dependencies [[org.clojure/clojure "1.10.3"] + [clj-http "3.12.3"] + [org.clojure/core.async "1.7.701"] + [com.cemerick/pomegranate "1.1.0"] + [net.runelite/client "1.10.49"] + [net.runelite/cache "1.10.49"] + #_[org.projectlombok/lombok "1.18.32"] + #_[javassist/javassist "3.12.1.GA"] + #_[net.sf.jopt-simple/jopt-simple "5.0.4"] + #_[com.github.joonasvali.naturalmouse/naturalmouse "2.0.3"] + #_[com.github.OSRSB/OSRSBPlugin "main-SNAPSHOT"]] + :repositories {"runelite" "https://repo.runelite.net" + "jitpack" "https://jitpack.io" + "central" "https://repo1.maven.org/maven2/"} + :jvm-opts ["--add-opens=java.base/java.lang=ALL-UNNAMED"] + :source-paths ["src/main/clojure"] + #_:java-source-paths #_["src/main/java"] + :javac-options ["-processor" "lombok.launch.AnnotationProcessorHider$AnnotationProcessor"] + :main net.runelite.rsb.launcher.core) \ No newline at end of file diff --git a/src/main/clojure/net/runelite/rsb/launcher/application.clj b/src/main/clojure/net/runelite/rsb/launcher/application.clj new file mode 100644 index 00000000..42fc7d02 --- /dev/null +++ b/src/main/clojure/net/runelite/rsb/launcher/application.clj @@ -0,0 +1,59 @@ +(ns net.runelite.rsb.launcher.application + (:require [clojure.core.async :as async :refer [chan go !! close!]] + [clojure.string :as str] + [net.runelite.rsb.launcher.botlite :as botlite]) + (:import #_[net.runelite.rsb.botLauncher BotLite])) + +(def bots []) + +(defn get-classloader + "Gets the classloader of an object." + [obj] + ((.getClassLoader (.getClass obj)))) + +(defn get-bot + "Retrieves the Bot for any object loaded in its client." + [obj] + (doseq [bot bots] + (when (== (get-classloader obj) (get-classloader bot)) + bot))) + +(defn add-bot + "" + [show-ui] + (let [bot (botlite/create-botlite-instance show-ui)] + (println bot) + (println "Test") + #_(.launch bot (into-array String ["--bot-runelite" "--developer-mode"])) + #_(conj bots bot))) + +(defn command-line-listener + "Handles command-line interfacing with the client. + The REPL is likely to be more immediately useful in most cases." + [] + (go (loop [command (str/trim (read-line))] + (case (first (str/split (str/lower-case command) #" ")) + "runscript" (println "runscript") + "stopscript" (println "stopscript") + "addbot" (do + (println "Adding bot") + (add-bot true)) + "checkstate" (println "checkstate") + (println "Invalid command")) + (recur (str/trim (read-line)))))) + +(defn start + "Parses command-line arguments passed to the program and then passes the remaining + to the command-line-listener method to continue handling the next inputs if applicable." + [args] + (println args) + (cond + (contains? args "--bot-runelite") + (do + (add-bot true) + (command-line-listener)) + (contains? args "--salsa-bowl") + (println "Random Behavior") + #_(println "S") + #_(.main Runelite (into-array String args)))) + diff --git a/src/main/clojure/net/runelite/rsb/launcher/botlite.clj b/src/main/clojure/net/runelite/rsb/launcher/botlite.clj new file mode 100644 index 00000000..31af0ef5 --- /dev/null +++ b/src/main/clojure/net/runelite/rsb/launcher/botlite.clj @@ -0,0 +1,102 @@ +(ns net.runelite.rsb.launcher.botlite + (:require [clojure.core.async :as async :refer [chan go >! !! close!]] + [clj-http.client :as client] + [clojure.java.shell :refer [sh]] + [clojure.string :as str] + [clojure.java.io :as io] + [cemerick.pomegranate :as pomegranate] + [cemerick.pomegranate.aether :as aether]) + (:import + [clojure.lang DynamicClassLoader] + [java.io File])) + +(defn classloader-classpath [classloader] + (->> (seq (.getURLs classloader)) + (map #(.getPath %)) + (clojure.string/join ":"))) + +(defn get-runelite-version [] + (let [url "http://repo.runelite.net/net/runelite/client/maven-metadata.xml" + response (client/get url {:as :stream})] + (with-open [reader (io/reader (:body response))] + (some #(when (str/includes? % "") + (str/trim (str/replace % #"" ""))) + (line-seq reader))))) + +(defn add-dependency [classloader group-id artifact-id version] + (pomegranate/add-dependencies + :classloader classloader + :coordinates [[(symbol (str group-id "/" artifact-id)) version]] + :repositories (merge aether/maven-central + {"clojars" "https://repo.clojars.org/" + "jitpack" "https://jitpack.io" + "central" "https://repo1.maven.org/maven2/" + "runelite" "https://repo.runelite.net"}))) + + +(defn find-lombok-jar [classloader] + (->> (seq (.getURLs classloader)) + (map #(.getPath %)) + (filter #(re-matches #".*lombok-.*\.jar$" %)) + first)) + + +(defn compile-java-files [classloader] + (spit "java-files.txt" + (str/join "\n" + (map #(.getPath %) + (filter #(str/ends-with? (.getName %) ".java") + (file-seq (io/file "src/main/java")))))) + (let [lombok-jar (find-lombok-jar classloader) + processorpath (if lombok-jar + lombok-jar + (throw (Exception. "Lombok JAR not found on classpath")))] + (sh "javac" "-d" "output" "-cp" (classloader-classpath classloader) "-processorpath" processorpath "@java-files.txt"))) + +(defn handle-deps [classloader] + (add-dependency classloader "net.runelite" "client" (get-runelite-version)) + (add-dependency classloader "net.runelite" "cache" (get-runelite-version)) + (add-dependency classloader "org.clojure" "clojure" "1.10.3") + (add-dependency classloader "org.slf4j" "slf4j-simple" "1.7.36") + (add-dependency classloader "org.projectlombok" "lombok" "1.18.32") + (add-dependency classloader "com.github.joonasvali.naturalmouse" "naturalmouse" "2.0.3") + (add-dependency classloader "com.github.OSRSB" "OSRSBPlugin" "main-SNAPSHOT") + (add-dependency classloader "javassist" "javassist" "3.12.1.GA") + (add-dependency classloader "net.sf.jopt-simple" "jopt-simple" "5.0.4")) + +(defn instantiate-class [lc] + (.newInstance lc)) + +(defn get-injector [lc] + (let [injector (.getDeclaredField lc "injector")] + (.setAccessible injector true) + (.get injector nil))) + +(def output-dir (File. "output")) + +(defn list-all-dirs [dir] + (let [dirs (file-seq dir)] + (filter #(.isDirectory %) dirs))) + +(defn add-dirs-to-classloader [classloader dirs] + (doseq [dir dirs] + (let [url (.toURL (.toURI dir))] + (.addURL classloader url)))) + +(defn create-botlite-instance [show-ui] + (let [class-name "net.runelite.rsb.botLauncher.BotLite" + class-loader (DynamicClassLoader. (ClassLoader/getSystemClassLoader)) + deps (handle-deps class-loader) + outputDeps (add-dirs-to-classloader class-loader (list-all-dirs output-dir)) + javaDeps (compile-java-files class-loader) + loaded-class (.loadClass class-loader class-name) + emptylite (instantiate-class loaded-class) + test (.launch emptylite (into-array String ["--bot-runelite" "--developer-mode"])) + botlite (.getInjectorInstance emptylite)] + #_(.launch botlite (into-array String ["--bot-runelite" "--developer-mode"])) + (.init botlite true) + {:class-loader class-loader + :loaded-class loaded-class + :class-name class-name + :empty-class emptylite + :botlite botlite})) \ No newline at end of file diff --git a/src/main/clojure/net/runelite/rsb/launcher/core.clj b/src/main/clojure/net/runelite/rsb/launcher/core.clj new file mode 100644 index 00000000..0fbd0c79 --- /dev/null +++ b/src/main/clojure/net/runelite/rsb/launcher/core.clj @@ -0,0 +1,42 @@ +(ns net.runelite.rsb.launcher.core + (:require [clj-http.client :as client] + [clojure.java.io :as io] [clojure.string :as str] + [cemerick.pomegranate :as pomegranate] + [cemerick.pomegranate.aether :as aether] + [net.runelite.rsb.launcher.application :as app] + ) + (:import [net.runelite.rsb.botLauncher Application]) + (:gen-class)) + +(defn get-runelite-version [] + (let [url "http://repo.runelite.net/net/runelite/client/maven-metadata.xml" + response (client/get url {:as :stream})] + (with-open [reader (io/reader (:body response))] + (some #(when (str/includes? % "") + (str/trim (str/replace % #"" ""))) + (line-seq reader))))) + +(defn add-dependency [group-id artifact-id version] + (let [current-thread (Thread/currentThread) + context-loader (.getContextClassLoader current-thread)] + (try + (.setContextClassLoader current-thread (clojure.lang.DynamicClassLoader. context-loader)) + (pomegranate/add-dependencies + :coordinates [[(symbol (str group-id "/" artifact-id)) version]] + :repositories (merge aether/maven-central + {"clojars" "https://repo.clojars.org/" + "runelite" "https://repo.runelite.net"})) + (finally + (.setContextClassLoader current-thread context-loader))))) + +(defn handle-deps [] + (add-dependency "net.runelite" "client" (get-runelite-version)) + (add-dependency "net.runelite" "cache" (get-runelite-version)) + (add-dependency "org.projectlombok" "lombok" "1.18.24") + (add-dependency "javassist" "javassist" "3.12.1.GA") + (add-dependency "net.sf.jopt-simple" "jopt-simple" "5.0.4")) + +(defn -main [& args] + (handle-deps) ;; This will be used when we convert ALL code from Java and can do runtime compilation only + (app/start (set args)) + #_(Application/main (into-array String args))) \ No newline at end of file diff --git a/src/main/java/net/runelite/rsb/botLauncher/Application.java b/src/main/java/net/runelite/rsb/botLauncher/Application.java index 1d4b2ecf..3f0da981 100644 --- a/src/main/java/net/runelite/rsb/botLauncher/Application.java +++ b/src/main/java/net/runelite/rsb/botLauncher/Application.java @@ -26,11 +26,10 @@ public class Application { * @throws Throwable Any error that might be thrown */ public static void main(final String[] args) throws Throwable { - JnREPL.startRepl(); preParser = new ArgumentPreParser(args); if (preParser.contains("--bot-runelite")) { addBot(preParser.contains("--headless")); - checkForCacheAndLoad(); + // checkForCacheAndLoad(); CLIHandler.handleCLI(); } else { net.runelite.client.RuneLite.main(args); diff --git a/src/main/java/net/runelite/rsb/wrappers/client_wrapper/BaseClientWrapper.java b/src/main/java/net/runelite/rsb/wrappers/client_wrapper/BaseClientWrapper.java index f48438e9..1b7d7890 100644 --- a/src/main/java/net/runelite/rsb/wrappers/client_wrapper/BaseClientWrapper.java +++ b/src/main/java/net/runelite/rsb/wrappers/client_wrapper/BaseClientWrapper.java @@ -1,8 +1,6 @@ package net.runelite.rsb.wrappers.client_wrapper; import net.runelite.api.*; -import net.runelite.api.Menu; -import net.runelite.api.Point; import net.runelite.api.annotations.Varp; import net.runelite.api.clan.ClanChannel; import net.runelite.api.clan.ClanSettings; @@ -17,21 +15,31 @@ import net.runelite.api.widgets.WidgetModalMode; import net.runelite.api.worldmap.MapElementConfig; import net.runelite.api.worldmap.WorldMap; +import net.runelite.api.RuneLiteObjectController; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.applet.Applet; import java.awt.*; +import java.lang.reflect.Method; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.function.IntPredicate; +import com.jagex.oldscape.pub.OAuthApi; +import com.jagex.oldscape.pub.OtlTokenRequester; +import com.jagex.oldscape.pub.OtlTokenResponse; + + + + /* Base class for wrapping runelite Client, along with some weird Applet shenanigans. */ @SuppressWarnings("removal") -public abstract class BaseClientWrapper extends Applet implements Client { +public abstract class BaseClientWrapper extends Applet implements Client, OAuthApi +{ public final Client wrappedClient; public BaseClientWrapper(Client client) { @@ -263,7 +271,7 @@ public int getScale() { } @Override - public Point getMouseCanvasPosition() { + public net.runelite.api.Point getMouseCanvasPosition() { return wrappedClient.getMouseCanvasPosition(); } @@ -1587,7 +1595,7 @@ public void setFreeCameraSpeed(int i) { } @Override - public Menu getMenu() { + public net.runelite.api.Menu getMenu() { return wrappedClient.getMenu(); } @@ -1620,4 +1628,34 @@ public WorldView getWorldView(int i) { public WorldView getTopLevelWorldView() { return wrappedClient.getTopLevelWorldView(); } + + @Override + public Model applyTransformations(Model m, Animation animA, int frameA, Animation animB, int frameB) { + return wrappedClient.applyTransformations(m, animA, frameA, animB, frameB); + } + + @Override + public void setDraw2DMask(int mask) { + wrappedClient.setDraw2DMask(mask); + } + + @Override + public int getDraw2DMask() { + return wrappedClient.getDraw2DMask(); + } + + @Override + public List getActiveMidiRequests() { + return wrappedClient.getActiveMidiRequests(); + } + + @Override + public boolean isRuneLiteObjectRegistered(RuneLiteObjectController controller) {return wrappedClient.isRuneLiteObjectRegistered(controller);} + + @Override + public void removeRuneLiteObject(RuneLiteObjectController controller) {wrappedClient.removeRuneLiteObject(controller);} + + @Override + public void registerRuneLiteObject(RuneLiteObjectController controller) {wrappedClient.registerRuneLiteObject(controller);} + } diff --git a/src/main/java/net/runelite/rsb/wrappers/client_wrapper/BaseWidgetWrapper.java b/src/main/java/net/runelite/rsb/wrappers/client_wrapper/BaseWidgetWrapper.java index e45131cb..2bd8691d 100644 --- a/src/main/java/net/runelite/rsb/wrappers/client_wrapper/BaseWidgetWrapper.java +++ b/src/main/java/net/runelite/rsb/wrappers/client_wrapper/BaseWidgetWrapper.java @@ -779,4 +779,8 @@ public void setOnScrollWheelListener(Object... objects) { @Override public void clearActions() { wrappedWidget.clearActions(); } + + @Override + public int[] getVarTransmitTrigger() { return wrappedWidget.getVarTransmitTrigger(); } + } diff --git a/src/main/java/net/runelite/rsb/wrappers/client_wrapper/RSClient.java b/src/main/java/net/runelite/rsb/wrappers/client_wrapper/RSClient.java index e62dbda1..a32d3fbb 100644 --- a/src/main/java/net/runelite/rsb/wrappers/client_wrapper/RSClient.java +++ b/src/main/java/net/runelite/rsb/wrappers/client_wrapper/RSClient.java @@ -7,7 +7,11 @@ import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.worldmap.MapElementConfig; import net.runelite.client.callback.ClientThread; - +import net.runelite.api.RuneLiteObjectController; +import com.jagex.oldscape.pub.OAuthApi; +import com.jagex.oldscape.pub.OtlTokenRequester; +import com.jagex.oldscape.pub.OtlTokenResponse; +import com.jagex.oldscape.pub.RefreshAccessTokenRequester; import javax.annotation.Nullable; import java.time.Instant; import java.util.*; @@ -24,427 +28,137 @@ public class RSClient extends BaseClientWrapper { private final Queue> taskQueue = new ConcurrentLinkedQueue<>(); - public RSClient(Client client, ClientThread clientThread) { - super(client); - clientThread.invoke(() -> { - final var expirationTime = Instant.now().plusMillis(20); - if (taskQueue.isEmpty()) return false; - while (Instant.now().isBefore(expirationTime)) { - final var task = taskQueue.poll(); - if (task != null) { - task.run(); - } - } - return false; - }); - } + private class WidgetWrapper extends BaseWidgetWrapper { - private void runTask(FutureTask task) { - if (super.isClientThread()) { - task.run(); - } else { - taskQueue.add(task); + WidgetWrapper(Widget widget) { + super(widget); } - } - @SneakyThrows - private void runOnClientThread(Runnable method) { - final var task = new FutureTask(() -> { method.run();return null; } ); - runTask(task); - task.get(); - } - - private T convertResult(T result) { - if (result instanceof Widget concreteResult) { - return (T) new WidgetWrapper(concreteResult); - } else if (result instanceof Widget[] concreteResult) { - WidgetWrapper[] convertedResult = new WidgetWrapper[concreteResult.length]; - for (int i = 0 ; i < concreteResult.length ; i++) { - convertedResult[i] = new WidgetWrapper(concreteResult[i]); - } - return (T) convertedResult; + @Override + public Widget getParent() { // tested, causes freezes without runOnClientThread + return runOnClientThread(super::getParent); } - return result; - } - private Widget[] convertArg(Widget[] arg) { - Widget[] convertedArg = new Widget[arg.length]; - for (int i = 0 ; i < arg.length ; i++) { - if (arg[i] instanceof WidgetWrapper widgetWrapper) { - convertedArg[i] = widgetWrapper.wrappedWidget; - } else { - convertedArg[i] = arg[i]; - } + @Override + public int getParentId() { // tested, causes freezes without runOnClientThread + return runOnClientThread(super::getParentId); } - return convertedArg; - } - @SneakyThrows - private T runOnClientThread(Callable method) { - final var task = new FutureTask(() -> convertResult(method.call())); - runTask(task); - return (T) task.get(); - } + @Override + public Widget setContentType(int contentType) { + return convertResult((super.setContentType(contentType))); + } - @Override - @Nullable - public Widget getDraggedWidget() { // tested, no need to runOnClientThread - return convertResult(super.getDraggedWidget()); - } + @Override + public Widget setClickMask(int mask) { + return convertResult(super.setClickMask(mask)); + } - @Override - @Nullable - public Widget getDraggedOnWidget() { // tested, no need to runOnClientThread - return convertResult(super.getDraggedOnWidget()); - } + @Override + public Widget getChild(int index) { + return convertResult(super.getChild(index)); + } - @Override - public void setDraggedOnWidget(Widget widget) { - super.setDraggedOnWidget(((WidgetWrapper) widget).wrappedWidget); - } + @Override + @Nullable + public Widget[] getChildren() { + return convertResult(super.getChildren()); + } - @Override - public Widget[] getWidgetRoots() { // tested, no need to runOnClientThread - return convertResult(super.getWidgetRoots()); - } + @Override + public void setChildren(Widget[] children) { + super.setChildren(convertArg(children)); + } - @SneakyThrows - @Override - @Nullable - public Widget getWidget(WidgetInfo widget) { // tested, no need to runOnClientThread - return convertResult(super.getWidget(widget)); - } + @Override + public Widget[] getDynamicChildren() { // tested, no need to runOnClientThread + return convertResult(super.getDynamicChildren()); + } - @Override - @Nullable - public Widget getWidget(int groupId, int childId) { // tested, no need to runOnClientThread - return convertResult(super.getWidget(groupId, childId)); - } + @Override + public Widget[] getStaticChildren() { // tested, no need to runOnClientThread + return convertResult(super.getStaticChildren()); + } - @Override - @Nullable - public Widget getWidget(int packedID) { // tested, no need to runOnClientThread - return convertResult(super.getWidget(packedID)); - } - @Override - public MapElementConfig getMapElementConfig(int id) { - return convertResult(super.getMapElementConfig(id)); - } + @Override + public Widget[] getNestedChildren() { // tested, no need to runOnClientThread + return convertResult(super.getNestedChildren()); + } - @Override - public Widget getScriptActiveWidget() { - return convertResult(super.getScriptActiveWidget()); - } + @Override + public Widget setText(String text) { + return convertResult(super.setText(text)); + } - @Override - public Widget getScriptDotWidget() { - return convertResult(super.getScriptDotWidget()); - } + @Override + public Widget setTextColor(int textColor) { + return convertResult(super.setTextColor(textColor)); + } - @Override - public void setCameraSpeed(float v) { - super.setCameraSpeed(v); - } + @Override + public Widget setOpacity(int transparency) { + return convertResult(super.setOpacity(transparency)); + } - @Override - public void setCameraMouseButtonMask(int i) { - super.setCameraMouseButtonMask(i); - } + @Override + public Widget setName(String name) { + return convertResult(super.setName(name)); + } - @Override - @Deprecated - public RenderOverview getRenderOverview() { - return super.getRenderOverview(); - } + @Override + public Widget setModelId(int id) { + return convertResult(super.setModelId(id)); + } - @Override - public void setHintArrow(LocalPoint point) { - super.setHintArrow(point); - } + @Override + public Widget setModelType(int type) { + return convertResult(super.setModelType(type)); + } - @Override - public IntPredicate getAnimationInterpolationFilter() { - return super.getAnimationInterpolationFilter(); - } + @Override + public Widget setAnimationId(int animationId) { + return convertResult(super.setAnimationId(animationId)); + } - @Override - public void setAnimationInterpolationFilter(IntPredicate intPredicate) { - super.setAnimationInterpolationFilter(intPredicate); - } + @Override + public Widget setRotationX(int modelX) { + return convertResult(super.setRotationX(modelX)); + } - @Override - public int getCameraMode() { - return super.getCameraMode(); - } + @Override + public Widget setRotationY(int modelY) { + return convertResult(super.setRotationY(modelY)); + } - @Override - public void setCameraMode(int i) { - super.setCameraMode(i); - } + @Override + public Widget setRotationZ(int modelZ) { + return convertResult(super.setRotationZ(modelZ)); + } - @Override - public double getCameraFocalPointX() { - return super.getCameraFocalPointX(); - } + @Override + public Widget setModelZoom(int modelZoom) { + return convertResult(super.setModelZoom(modelZoom)); + } - @Override - public void setCameraFocalPointX(double v) { - super.setCameraFocalPointX(v); - } + @Override + public Widget setSpriteTiling(boolean tiling) { + return convertResult(super.setSpriteTiling(tiling)); + } - @Override - public void setCameraFocalPointY(double v) { - super.setCameraFocalPointY(v); - } + @Override + public Widget setSpriteId(int spriteId) { + return convertResult(super.setSpriteId(spriteId)); + } - @Override - public double getCameraFocalPointZ() { - return super.getCameraFocalPointZ(); - } + @Override + public Widget setHidden(boolean hidden) { + return convertResult(super.setHidden(hidden)); + } - @Override - public void setFreeCameraSpeed(int i) { - super.setFreeCameraSpeed(i); - } - - @Override - public void checkClickbox(Projection projection, Model model, int i, int i1, int i2, int i3, long l) { - super.checkClickbox(projection, model, i, i1, i2, i3, l); - } - - @Override - public double getCameraFocalPointY() { - return super.getCameraFocalPointY(); - } - - @Override - public boolean isWidgetSelected() {return super.isWidgetSelected();} - - @Override - @Nullable - public Widget getSelectedWidget() { - return convertResult(super.getSelectedWidget()); - } - - @Override - public void setWidgetSelected(boolean selected) { - super.setWidgetSelected(selected); - } - - @Override - public void setIdleTimeout(int ticks) { - super.setIdleTimeout(ticks); - } - - @Override - public int getIdleTimeout() { - return convertResult(super.getIdleTimeout()); - } - - @Override - public void setMinimapTileDrawer(TileFunction drawTile) { - super.setMinimapTileDrawer(drawTile); - } - - @Override - public void setCameraShakeDisabled(boolean b) { - super.setCameraShakeDisabled(b); - } - - @Override - public boolean isCameraShakeDisabled() { - return super.isCameraShakeDisabled(); - } - - @Override - public Menu getMenu() { - return super.getMenu(); - } - - @Override - public Rasterizer getRasterizer() { - return super.getRasterizer(); - } - - @Override - public void menuAction(int i, int i1, MenuAction menuAction, int i2, int i3, String s, String s1) { - super.menuAction(i, i1, menuAction, i2, i3, s, s1); - } - - @Override - public WorldView getWorldView(int i) { - return convertResult(super.getWorldView(i)); - } - - @Override - public WorldView getTopLevelWorldView() { - return convertResult(super.getTopLevelWorldView()); - } - - @Nullable - @Override - public LocalPoint getLocalDestinationLocation() { // tested, causes freezes without runOnClientThread - return runOnClientThread(super::getLocalDestinationLocation); - } - - @Override - public int getArraySizes(int i) { - return super.getArraySizes(i); - } - - @Override - public int[] getArray(int i) { - return super.getArray(i); - } - - @Nullable - @Override - public String getLauncherDisplayName() { - return super.getLauncherDisplayName(); - } - - @Override - public Player getLocalPlayer() { // tested, causes freezes without runOnClientThread - return runOnClientThread(super::getLocalPlayer); - } - - @Nullable - @Override - public CollisionData[] getCollisionMaps() { // tested, causes freezes without runOnClientThread - return runOnClientThread(super::getCollisionMaps); - } - - private class WidgetWrapper extends BaseWidgetWrapper { - - WidgetWrapper(Widget widget) { - super(widget); - } - - @Override - public Widget getParent() { // tested, causes freezes without runOnClientThread - return runOnClientThread(super::getParent); - } - - @Override - public int getParentId() { // tested, causes freezes without runOnClientThread - return runOnClientThread(super::getParentId); - } - - @Override - public Widget setContentType(int contentType) { - return convertResult((super.setContentType(contentType))); - } - - @Override - public Widget setClickMask(int mask) { - return convertResult(super.setClickMask(mask)); - } - - @Override - public Widget getChild(int index) { - return convertResult(super.getChild(index)); - } - - @Override - @Nullable - public Widget[] getChildren() { - return convertResult(super.getChildren()); - } - - @Override - public void setChildren(Widget[] children) { - super.setChildren(convertArg(children)); - } - - @Override - public Widget[] getDynamicChildren() { // tested, no need to runOnClientThread - return convertResult(super.getDynamicChildren()); - } - - @Override - public Widget[] getStaticChildren() { // tested, no need to runOnClientThread - return convertResult(super.getStaticChildren()); - } - - @Override - public Widget[] getNestedChildren() { // tested, no need to runOnClientThread - return convertResult(super.getNestedChildren()); - } - - @Override - public Widget setText(String text) { - return convertResult(super.setText(text)); - } - - @Override - public Widget setTextColor(int textColor) { - return convertResult(super.setTextColor(textColor)); - } - - @Override - public Widget setOpacity(int transparency) { - return convertResult(super.setOpacity(transparency)); - } - - @Override - public Widget setName(String name) { - return convertResult(super.setName(name)); - } - - @Override - public Widget setModelId(int id) { - return convertResult(super.setModelId(id)); - } - - @Override - public Widget setModelType(int type) { - return convertResult(super.setModelType(type)); - } - - @Override - public Widget setAnimationId(int animationId) { - return convertResult(super.setAnimationId(animationId)); - } - - @Override - public Widget setRotationX(int modelX) { - return convertResult(super.setRotationX(modelX)); - } - - @Override - public Widget setRotationY(int modelY) { - return convertResult(super.setRotationY(modelY)); - } - - @Override - public Widget setRotationZ(int modelZ) { - return convertResult(super.setRotationZ(modelZ)); - } - - @Override - public Widget setModelZoom(int modelZoom) { - return convertResult(super.setModelZoom(modelZoom)); - } - - @Override - public Widget setSpriteTiling(boolean tiling) { - return convertResult(super.setSpriteTiling(tiling)); - } - - @Override - public Widget setSpriteId(int spriteId) { - return convertResult(super.setSpriteId(spriteId)); - } - - @Override - public Widget setHidden(boolean hidden) { - return convertResult(super.setHidden(hidden)); - } - - @Override - public Widget setItemId(int itemId) { - return convertResult(super.setItemId(itemId)); - } + @Override + public Widget setItemId(int itemId) { + return convertResult(super.setItemId(itemId)); + } @Override public Widget setItemQuantity(int quantity) { @@ -600,5 +314,388 @@ public Widget setDragParent(Widget dragParent) { public void clearActions() { super.clearActions(); } + + @Override + public int[] getVarTransmitTrigger() { + return super.getVarTransmitTrigger(); + } } + + + public RSClient(Client client, ClientThread clientThread) { + super(client); + clientThread.invoke(() -> { + final var expirationTime = Instant.now().plusMillis(20); + if (taskQueue.isEmpty()) return false; + while (Instant.now().isBefore(expirationTime)) { + final var task = taskQueue.poll(); + if (task != null) { + task.run(); + } + } + return false; + }); + } + + private void runTask(FutureTask task) { + if (super.isClientThread()) { + task.run(); + } else { + taskQueue.add(task); + } + } + + @SneakyThrows + private void runOnClientThread(Runnable method) { + final var task = new FutureTask(() -> { method.run();return null; } ); + runTask(task); + task.get(); + } + + private T convertResult(T result) { + if (result instanceof Widget concreteResult) { + return (T) new WidgetWrapper(concreteResult); + } else if (result instanceof Widget[] concreteResult) { + WidgetWrapper[] convertedResult = new WidgetWrapper[concreteResult.length]; + for (int i = 0 ; i < concreteResult.length ; i++) { + convertedResult[i] = new WidgetWrapper(concreteResult[i]); + } + return (T) convertedResult; + } + return result; + } + + private Widget[] convertArg(Widget[] arg) { + Widget[] convertedArg = new Widget[arg.length]; + for (int i = 0 ; i < arg.length ; i++) { + if (arg[i] instanceof WidgetWrapper widgetWrapper) { + convertedArg[i] = widgetWrapper.wrappedWidget; + } else { + convertedArg[i] = arg[i]; + } + } + return convertedArg; + } + + @SneakyThrows + private T runOnClientThread(Callable method) { + final var task = new FutureTask(() -> convertResult(method.call())); + runTask(task); + return (T) task.get(); + } + + @Override + @Nullable + public Widget getDraggedWidget() { // tested, no need to runOnClientThread + return convertResult(super.getDraggedWidget()); + } + + @Override + @Nullable + public Widget getDraggedOnWidget() { // tested, no need to runOnClientThread + return convertResult(super.getDraggedOnWidget()); + } + + @Override + public void setDraggedOnWidget(Widget widget) { + super.setDraggedOnWidget(((WidgetWrapper) widget).wrappedWidget); + } + + @Override + public Widget[] getWidgetRoots() { // tested, no need to runOnClientThread + return convertResult(super.getWidgetRoots()); + } + + @SneakyThrows + @Override + @Nullable + public Widget getWidget(WidgetInfo widget) { // tested, no need to runOnClientThread + return convertResult(super.getWidget(widget)); + } + + @Override + @Nullable + public Widget getWidget(int groupId, int childId) { // tested, no need to runOnClientThread + return convertResult(super.getWidget(groupId, childId)); + } + + @Override + @Nullable + public Widget getWidget(int packedID) { // tested, no need to runOnClientThread + return convertResult(super.getWidget(packedID)); + } + @Override + public MapElementConfig getMapElementConfig(int id) { + return convertResult(super.getMapElementConfig(id)); + } + + @Override + public Widget getScriptActiveWidget() { + return convertResult(super.getScriptActiveWidget()); + } + + @Override + public Widget getScriptDotWidget() { + return convertResult(super.getScriptDotWidget()); + } + + @Override + public void setCameraSpeed(float v) { + super.setCameraSpeed(v); + } + + @Override + public void setCameraMouseButtonMask(int i) { + super.setCameraMouseButtonMask(i); + } + + @Override + @Deprecated + public RenderOverview getRenderOverview() { + return super.getRenderOverview(); + } + + @Override + public void setHintArrow(LocalPoint point) { + super.setHintArrow(point); + } + + @Override + public IntPredicate getAnimationInterpolationFilter() { + return super.getAnimationInterpolationFilter(); + } + + @Override + public void setAnimationInterpolationFilter(IntPredicate intPredicate) { + super.setAnimationInterpolationFilter(intPredicate); + } + + @Override + public int getCameraMode() { + return super.getCameraMode(); + } + + @Override + public void setCameraMode(int i) { + super.setCameraMode(i); + } + + @Override + public double getCameraFocalPointX() { + return super.getCameraFocalPointX(); + } + + @Override + public void setCameraFocalPointX(double v) { + super.setCameraFocalPointX(v); + } + + @Override + public void setCameraFocalPointY(double v) { + super.setCameraFocalPointY(v); + } + + @Override + public double getCameraFocalPointZ() { + return super.getCameraFocalPointZ(); + } + + @Override + public void setFreeCameraSpeed(int i) { + super.setFreeCameraSpeed(i); + } + + @Override + public void checkClickbox(Projection projection, Model model, int i, int i1, int i2, int i3, long l) { + super.checkClickbox(projection, model, i, i1, i2, i3, l); + } + + @Override + public double getCameraFocalPointY() { + return super.getCameraFocalPointY(); + } + + @Override + public boolean isWidgetSelected() {return super.isWidgetSelected();} + + @Override + @Nullable + public Widget getSelectedWidget() { + return convertResult(super.getSelectedWidget()); + } + + @Override + public void setWidgetSelected(boolean selected) { + super.setWidgetSelected(selected); + } + + @Override + public void setIdleTimeout(int ticks) { + super.setIdleTimeout(ticks); + } + + @Override + public int getIdleTimeout() { + return convertResult(super.getIdleTimeout()); + } + + @Override + public void setMinimapTileDrawer(TileFunction drawTile) { + super.setMinimapTileDrawer(drawTile); + } + + @Override + public void setCameraShakeDisabled(boolean b) { + super.setCameraShakeDisabled(b); + } + + @Override + public boolean isCameraShakeDisabled() { + return super.isCameraShakeDisabled(); + } + + @Override + public Menu getMenu() { + return super.getMenu(); + } + + @Override + public Rasterizer getRasterizer() { + return super.getRasterizer(); + } + + @Override + public void menuAction(int i, int i1, MenuAction menuAction, int i2, int i3, String s, String s1) { + super.menuAction(i, i1, menuAction, i2, i3, s, s1); + } + + @Override + public WorldView getWorldView(int i) { + return convertResult(super.getWorldView(i)); + } + + @Override + public WorldView getTopLevelWorldView() { + return convertResult(super.getTopLevelWorldView()); + } + + @Nullable + @Override + public LocalPoint getLocalDestinationLocation() { // tested, causes freezes without runOnClientThread + return runOnClientThread(super::getLocalDestinationLocation); + } + + @Override + public int getArraySizes(int i) { + return super.getArraySizes(i); + } + + @Override + public int[] getArray(int i) { + return super.getArray(i); + } + + @Nullable + @Override + public String getLauncherDisplayName() { + return super.getLauncherDisplayName(); + } + + @Override + public Player getLocalPlayer() { // tested, causes freezes without runOnClientThread + return runOnClientThread(super::getLocalPlayer); + } + + @Nullable + @Override + public CollisionData[] getCollisionMaps() { // tested, causes freezes without runOnClientThread + return runOnClientThread(super::getCollisionMaps); + } + + @Override + public Model applyTransformations(Model m, Animation animA, int frameA, Animation animB, int frameB) { + return super.applyTransformations(m, animA, frameA, animB, frameB); + } + + @Override + public void setDraw2DMask(int mask) { + super.setDraw2DMask(mask); + } + + @Override + public int getDraw2DMask() { + return super.getDraw2DMask(); + } + + @Override + public List getActiveMidiRequests() { + return convertResult(super.getActiveMidiRequests()); + } + + @Override + public boolean isRuneLiteObjectRegistered(RuneLiteObjectController controller) { + return super.isRuneLiteObjectRegistered(controller); + } + + @Override + public void removeRuneLiteObject(RuneLiteObjectController controller) { + super.removeRuneLiteObject(controller); + } + + @Override + public void registerRuneLiteObject(RuneLiteObjectController controller) { + super.registerRuneLiteObject(controller); + } + + public void px(OtlTokenRequester requester) { + px(requester); + } + + public long qx() { + return qx(); + } + + public boolean pz() { + return pz(); + } + + public boolean pi() { + return pi(); + } + + public boolean ps() { + return ps(); + } + + public void setOtlTokenRequester(OtlTokenRequester requester) { + setOtlTokenRequester(requester); + } + + public void pr(RefreshAccessTokenRequester requester) { + pr(requester); + } + + public void pn(OtlTokenRequester requester) { + pn(requester); + } + + public void pm(RefreshAccessTokenRequester requester) { + pm(requester); + } + + public void setRefreshTokenRequester(RefreshAccessTokenRequester requester) { + setRefreshTokenRequester(requester); + } + + + public void setClient(int client) { + setClient(client); + } + + public long qu() { return qu(); } + + public boolean isOnLoginScreen() { return isOnLoginScreen(); } + +public boolean pf() { return pf(); } +public void pg(int a) { pg(a); } }