- Joined
- Jan 17, 2017
- Messages
- 34
- Thread Author
- #1
I've been hanging around in the slack for a couple of days now and I feel like not enough people know how to properly perform 'sleeps' or delays as they are called in the Execution class.
What are delays
I assume most of you know whet delays are but just to make sure; delays are sleeps performed in your bots to ensure there is enough time between consecutive actions and to ensure an action is completed properly. These are the two cases I will describe to demonstrate the usage of delays.
The Execution class
The Execution class (see javadocs) contains all the methods we will require to properly set up delays. The methods you should use are (in most cases):
(so (!booleanValue1 && !booleanValue2) would become (booleanValue1 || booleanValue2))
However there may be cases where delayWhile is more appropriate (eventhough I cannot think of any right now)
How to use delayUntil
As said in the previous section, you can in most cases swap out delayWhile's for delayUntil's and therefore I will just explain how delayUntil should be used because it should give a good enough explanation of how delayWhile should be used.
The first thing I want to note is that I've left out the methods without a timeout and with a static timeout. Why? Because:
Ignore the actual item retrieval but let's focus on the delay method. Now as you can see if you're familiar with Java 8 I am using Lambda expressions so if you're not familiar with those please read up on them real quick and then continue reading here.
So as you can see (and should probably understand by now) this delayUntil method will wait for an inventory item to be selected, but if the time we are waiting for exceeds the randomly between 800 and 1200 selected timeout it will exit the waiting loop and our bot will try again. If our bot had for example miss clicked on our tinderbox and no item had been selected, the bot would have waited forever if it didn't have a timeout.
Now another useful thing to note, is that the delay methods will return true if they were exited because the condition was met, and will return false if delay was exited because the timeout was exceeded. This can be quite useful in situations where you need to know if an action was executed correctly. For example in our code we could use this to decide whether or not to click a log next:
I'll add a quick explanation of what the extra reset parameter does for, even though it's probably self explanatory. The reset callable will be checked every time the delay condition is checked to see if the timeout needs to be reset, if your reset callable returns true the 'internal run time' of the delay will be set to 0 and if it returns false it will simply not alter anything.
What does the delayUntil method look like in code?
If you want to be able to visualize what this method would look like in code, here's a short snippet that will probably be very similar to the actual implementation of Runemate:
Please use delays from now on, and make sure to use them properly!
Also props to me not using 'script'
What are delays
I assume most of you know whet delays are but just to make sure; delays are sleeps performed in your bots to ensure there is enough time between consecutive actions and to ensure an action is completed properly. These are the two cases I will describe to demonstrate the usage of delays.
The Execution class
The Execution class (see javadocs) contains all the methods we will require to properly set up delays. The methods you should use are (in most cases):
- delayUntil(Callable<java.lang.Boolean> condition, int minTimeout, int maxTimeout)
- delayUntil(Callable<java.lang.Boolean> condition, Callable<java.lang.Boolean> reset, int minTimeout, int maxTimeout)
- delayWhile(Callable<java.lang.Boolean> condition, Callable<java.lang.Boolean> reset, int minTimeout, int maxTimeout)
- delayWhile(java.util.concurrent.Callable<java.lang.Boolean> condition, int minTimeout, int maxTimeout)
(so (!booleanValue1 && !booleanValue2) would become (booleanValue1 || booleanValue2))
However there may be cases where delayWhile is more appropriate (eventhough I cannot think of any right now)
How to use delayUntil
As said in the previous section, you can in most cases swap out delayWhile's for delayUntil's and therefore I will just explain how delayUntil should be used because it should give a good enough explanation of how delayWhile should be used.
The first thing I want to note is that I've left out the methods without a timeout and with a static timeout. Why? Because:
- No timeout is a terrible idea, if anything goes wrong causing your condition to not return true your bot can't exit the loop it's stuck in which can allow the bot to 'repair' itself. Never delay without timeouts!
- A static timeout is not necessarily bad, however since we're writing bots here and we don't want Jagex to discover that there is a static aspect to our bots we should try to minimize these aspects wherever we can; delays are an example.
The usage of minTimeout and maxTimeout even if they are only 100ms apart can make a huge difference.
Code:
SpriteItemQueryResults result = Inventory.getItems("Tinderbox");
if (!result .isEmpty()) {
SpriteItem tinderbox = result.first();
if (tinderbox.click()) {
Execution.delayUntil(() -> Inventory.getSelectedItem() != null, 800, 1200);
}
}
Ignore the actual item retrieval but let's focus on the delay method. Now as you can see if you're familiar with Java 8 I am using Lambda expressions so if you're not familiar with those please read up on them real quick and then continue reading here.
So as you can see (and should probably understand by now) this delayUntil method will wait for an inventory item to be selected, but if the time we are waiting for exceeds the randomly between 800 and 1200 selected timeout it will exit the waiting loop and our bot will try again. If our bot had for example miss clicked on our tinderbox and no item had been selected, the bot would have waited forever if it didn't have a timeout.
Now another useful thing to note, is that the delay methods will return true if they were exited because the condition was met, and will return false if delay was exited because the timeout was exceeded. This can be quite useful in situations where you need to know if an action was executed correctly. For example in our code we could use this to decide whether or not to click a log next:
Code:
SpriteItemQueryResults result = Inventory.getItems("Tinderbox");
if (!result .isEmpty()) {
SpriteItem tinderbox = result.first();
if (tinderbox.click()) {
if (Execution.delayUntil(() -> Inventory.getSelectedItem() != null, 800, 1200)) {
//The condition was met
//Click our log here
}
}
}
I'll add a quick explanation of what the extra reset parameter does for, even though it's probably self explanatory. The reset callable will be checked every time the delay condition is checked to see if the timeout needs to be reset, if your reset callable returns true the 'internal run time' of the delay will be set to 0 and if it returns false it will simply not alter anything.
What does the delayUntil method look like in code?
If you want to be able to visualize what this method would look like in code, here's a short snippet that will probably be very similar to the actual implementation of Runemate:
Code:
public static boolean delayUntil(Callable<java.lang.Boolean> condition, Callable<Boolean> reset,
int frequency, int minTimeout, int maxTimeout) {
Random random = new Random();
int timeout = (int) (minTimeout + random.nextDouble() * maxTimeout);
try {
for (int timer = 0; timer < timeout; timer += frequency) {
//If the condition returns true, make the delay return true
if (condition.call())
return true;
//If the reset callable returns true, reset the timer 'i' to 0;
if (reset.call())
timer = 0;
//Perform the frequency delay
Execution.delay(frequency);
//Might be some actions here RuneMate wants to ensure that happen
}
} catch (Exception e) {
e.printStackTrace();
}
//The condition did not return true therefore the condition must not have s
return false;
}
Please use delays from now on, and make sure to use them properly!
Also props to me not using 'script'