Jarl Posted January 18, 2021 Share Posted January 18, 2021 I've been trying to do asynchronous tasks by using osbot's event and setting it as async, and using a runnable class to start a new thread. It seems to work well but I have some questions to ask. How do you pause other tasks or sleep the whole bot while on an async event/thread? Is there a proper way to do garbage collection for these async events/threads? (Seems like you can start/pause them but no proper way to "delete" them. I think this becomes a problem if you stop/start the script many times) Quote Link to comment Share on other sites More sharing options...
Nbacon Posted January 18, 2021 Share Posted January 18, 2021 Hello Jarl Im not an expert on threading at all. but This is how I did it in the past. 58 minutes ago, Jarl said: How do you pause other tasks or sleep the whole bot while on an async event/thread? Thread(){ While(true){ if (notpaused){ do stoof } Sleep(random(500,1500)) } } @Override public void pause() { notpaused =false } @Override public void resume() { notpaused =true } 58 minutes ago, Jarl said: Is there a proper way to do garbage collection for these async events/threads? (Seems like you can start/pause them but no proper way to "delete" them. I think this becomes a problem if you stop/start the script many times) Thread pools. https://www.geeksforgeeks.org/thread-pools-java/ https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html 1 Quote Link to comment Share on other sites More sharing options...
Token Posted January 18, 2021 Share Posted January 18, 2021 You will rarely need threads in scripts. I only use async events to correct API errors, e.g. force event termination for WebWalkEvent which used to take seconds to exit years ago. You should consider all possible approaches before resorting to threading. Threads may be justified as an abstraction of a specific task when you want to prioritize it, e.g. eating, which you decide to apply throughout the entire script and want to immediately stop whatever you were doing in order to eat. Background task; execute for as long as the script is executing; do not stop while random solver is executing or when user pauses the script Thread t = new Thread(() -> { while (getBot().getScriptExecutor().isRunning()) { // code try { Thread.sleep(69); } catch (InterruptedException e) { break; } } }); t.start(); Unknown iteration loop on script thread (do not use unless you can justify the need for this); stop when random solver kicks in or user presses pause/stop; the script executor conditions are added in order to make the pause/stop responsive in the case where the code you are executing catches the InterruptedException raised when they press those buttons; this shouldn't happen because that exception is not supposed to be caught, but adding these conditions prevents it from running forever (client buttons will not respond to clicks) if you want to be sure you don't get the client stuck and have to restart while (condition && getBot().getScriptExecutor().isRunning() && !getBot().getScriptExecutor().isPaused() && !getBot().getScriptExecutor().isSuspended()) { // ... } 1 Quote Link to comment Share on other sites More sharing options...
Jarl Posted January 19, 2021 Author Share Posted January 19, 2021 @Nbacon@TokenThanks for your responses. I was actually thinking of doing a thread while webwalking or during combat. I understand both your threads would work, but from my experience, I had the main thread and the async thread competing with each other to control the mouse to do their thing. Eventually it works out, I was worried about the weird mouse interactions and something potentially not working. Another thing I was thinking of was potentially using a thread to handle other stuff like chat (good for async since it doesn't control the mouse?) and random events (which needs the mouse). Is there a way to pause everything else instantly, when the thread "detects" something? 23 hours ago, Nbacon said: Thread pools. https://www.geeksforgeeks.org/thread-pools-java/ https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html Thanks for this. A good read, though not very useful for osbot since you would rarely need more than 1 thread. I found it useful elsewhere though. 20 hours ago, Token said: Unknown iteration loop on script thread (do not use unless you can justify the need for this); stop when random solver kicks in or user presses pause/stop; the script executor conditions are added in order to make the pause/stop responsive in the case where the code you are executing catches the InterruptedException raised when they press those buttons; this shouldn't happen because that exception is not supposed to be caught, but adding these conditions prevents it from running forever (client buttons will not respond to clicks) if you want to be sure you don't get the client stuck and have to restart Wouldn't this be similar to pausing the thread on exit/on pause/on resume? Quote Link to comment Share on other sites More sharing options...
Nbacon Posted January 19, 2021 Share Posted January 19, 2021 1 hour ago, Jarl said: doing a thread while webwalking or during combat This is the thread that I asked for help with amost the same thing. Ill look for the code and come back if i find it. Quote Link to comment Share on other sites More sharing options...
Jarl Posted January 19, 2021 Author Share Posted January 19, 2021 2 hours ago, Nbacon said: This is the thread that I asked for help with amost the same thing. That's interesting! I guess we were both thinking of gracefully pausing webwalk to eat/high alch/whatever and then resuming the webwalk immediately after. My naive solution would have been to "sleep" the main thread and continue executing the async thread, but I couldn't find a solution for that. 2 hours ago, Nbacon said: Ill look for the code and come back if i find it. Thanks so much Quote Link to comment Share on other sites More sharing options...
Camaro Posted January 20, 2021 Share Posted January 20, 2021 Here's a custom webwalk event class that I use to perform actions while walking without delays import org.osbot.rs07.api.map.Position; import org.osbot.rs07.event.WebWalkEvent; import org.osbot.rs07.utility.ConditionalSleep2; public class CustomWebWalk extends WebWalkEvent { private AsyncWalkEvent asyncWalkEvent; public CustomWebWalk(Position position) { super(position); } @Override public void onStart() { asyncWalkEvent = new AsyncWalkEvent(); execute(asyncWalkEvent); } @Override public int execute() throws InterruptedException { if (asyncWalkEvent.isLooping()) { // Async is still looping, dont let the web walker execute return 600; } return super.execute(); } @Override public void onEnd() throws InterruptedException { // End the async event and wait for it to finish asyncWalkEvent.setFinished(); ConditionalSleep2.sleep(5000, asyncWalkEvent::hasCompleted); } } And the action that executes in a separate thread import org.osbot.rs07.api.map.Position; import org.osbot.rs07.event.Event; public class AsyncWalkEvent extends Event { private volatile boolean finished = false; private volatile boolean isLooping = false; public AsyncWalkEvent() { setAsync(); } @Override public int execute() throws InterruptedException { if (canPerformAction()) { // Map destination is far enough away, we can perform some actions isLooping = true; if (shouldDoAction()) { // do action } else { // any other necessary action } isLooping = false; } return 600; } @Override public void onEnd() throws InterruptedException { finished = true; } public boolean isLooping() { return isLooping; } public boolean hasCompleted() { return finished; } private boolean canPerformAction() { // Only allow the actions to start if the map destination is far enough away Position dest = getMap().getDestination(); if (dest == null) return false; int dist = getMap().distance(dest); return dist < 20 && dist > 7; } } 2 Quote Link to comment Share on other sites More sharing options...
Nbacon Posted January 20, 2021 Share Posted January 20, 2021 interface ISOMETHING{ void onStart(); void execute(); void onEnd(); int time(); boolean testAsBoolean(); } public class d { boolean walkwalk(MethodProvider mp,int run, PathPreferenceProfile profile,boolean camera, Area area, ISOMETHING something) { WebWalkEvent walkEvent = new WebWalkEvent(area); walkEvent.setPathPreferenceProfile(profile); walkEvent.setEnergyThreshold(run); walkEvent.setMoveCameraDuringWalking(camera); Event event = new Event() { public void onStart() throws InterruptedException { this.setAsync(); something.onStart(); } public int execute() throws InterruptedException { if ( something.testAsBoolean()){ this.setBlocking();//impotant something.execute(); this.setAsync();//impotant } return something.time(); } public void onEnd() throws InterruptedException { something.onEnd(); } }; mp.execute(event); boolean done = mp.execute(walkEvent).hasFinished(); event.setFinished(); return done; } } 1 Quote Link to comment Share on other sites More sharing options...
Jarl Posted January 20, 2021 Author Share Posted January 20, 2021 (edited) @Camaro @NbaconThanks for your code snippets! Both are interesting approaches and I will put both to the test to see how it really interacts. Sadly, it looks like you cannot do something asynchronously throughout a script, unless you prepare extensively for it which might be too much work. Edited January 20, 2021 by Jarl 1 Quote Link to comment Share on other sites More sharing options...
Nbacon Posted January 20, 2021 Share Posted January 20, 2021 (edited) 29 minutes ago, Jarl said: . I know how that feels. Im writing a banking thing that I might post. The frist 95% took like 2 hours and the last 80% took like 10+hours... All so I don't have to write banking code ever again..... Edited January 20, 2021 by Nbacon Quote Link to comment Share on other sites More sharing options...
shaba123 Posted June 5, 2023 Share Posted June 5, 2023 On 1/20/2021 at 4:30 AM, Camaro said: Here's a custom webwalk event class that I use to perform actions while walking without delays import org.osbot.rs07.api.map.Position; import org.osbot.rs07.event.WebWalkEvent; import org.osbot.rs07.utility.ConditionalSleep2; public class CustomWebWalk extends WebWalkEvent { private AsyncWalkEvent asyncWalkEvent; public CustomWebWalk(Position position) { super(position); } @Override public void onStart() { asyncWalkEvent = new AsyncWalkEvent(); execute(asyncWalkEvent); } @Override public int execute() throws InterruptedException { if (asyncWalkEvent.isLooping()) { // Async is still looping, dont let the web walker execute return 600; } return super.execute(); } @Override public void onEnd() throws InterruptedException { // End the async event and wait for it to finish asyncWalkEvent.setFinished(); ConditionalSleep2.sleep(5000, asyncWalkEvent::hasCompleted); } } And the action that executes in a separate thread import org.osbot.rs07.api.map.Position; import org.osbot.rs07.event.Event; public class AsyncWalkEvent extends Event { private volatile boolean finished = false; private volatile boolean isLooping = false; public AsyncWalkEvent() { setAsync(); } @Override public int execute() throws InterruptedException { if (canPerformAction()) { // Map destination is far enough away, we can perform some actions isLooping = true; if (shouldDoAction()) { // do action } else { // any other necessary action } isLooping = false; } return 600; } @Override public void onEnd() throws InterruptedException { finished = true; } public boolean isLooping() { return isLooping; } public boolean hasCompleted() { return finished; } private boolean canPerformAction() { // Only allow the actions to start if the map destination is far enough away Position dest = getMap().getDestination(); if (dest == null) return false; int dist = getMap().distance(dest); return dist < 20 && dist > 7; } } hey this looks great how would i execute the customwebwalk in my script? Quote Link to comment Share on other sites More sharing options...