Jump to content

Custom Sleep Handler


Fanny

Recommended Posts

I have been trying to write an effective custom sleep handler - I have commented through the method to make it clearer what the purpose of each stage is.

I am having trouble with implementation on my latest attempt at a script - I find that when interacting it is tending to spam click when I don't expect that behaviour

Any advice? (also free sample code if anyone can make use of it! :))

 

CS.java

import org.osbot.rs07.utility.ConditionalSleep;
import java.util.Random;
import java.util.function.BooleanSupplier;
import org.osbot.rs07.script.Script;

public class CS extends ConditionalSleep {
    private final BooleanSupplier condition;
    private final Script script;
    private final int initialDurationMs;
    private final int additionalDurationMs;
    private final Random random = new Random();

    public CS(Script script, int initialDurationMs, int additionalDurationMs, BooleanSupplier condition) {
        super(initialDurationMs + additionalDurationMs);
        this.initialDurationMs = initialDurationMs;
        this.additionalDurationMs = additionalDurationMs;
        this.condition = condition;
        this.script = script;
    }

    @Override
    public boolean condition() throws InterruptedException {
        boolean mouseOutOfScreen = false;

        // Small chance to move mouse out of screen immediately
        if (random.nextDouble() < 0.03) {
            script.getMouse().moveOutsideScreen();
            mouseOutOfScreen = true;
        }

        // Capture the external condition to use inside the anonymous class
        BooleanSupplier localCondition = this.condition;

        // Small Sleep after action of ~ 300 - 800ms
        new ConditionalSleep(300 + random.nextInt(800 - 300), 100) {
            @Override
            public boolean condition() {
                return localCondition.getAsBoolean();
            }
        }.sleep();


        if(localCondition.getAsBoolean()) {

            // Small chance to move mouse out of screen after small wait
            if (random.nextDouble() < 0.10 && !mouseOutOfScreen) {
                script.getMouse().moveOutsideScreen();
                mouseOutOfScreen = true;
            }

            // Sleep after the event is already true
            new ConditionalSleep(this.additionalDurationMs, 100) {
                @Override
                public boolean condition() {
                    return false;
                }
            }.sleep();

        }
        else {
            // Larger chance to move mouse out of screen after the condition is still not true
            if (random.nextDouble() < 0.50 && !mouseOutOfScreen) {
                script.getMouse().moveOutsideScreen();
                mouseOutOfScreen = true;
            }

            // Sleep until the event is true, or until the timeout
            new ConditionalSleep(this.initialDurationMs, 100) {
                @Override
                public boolean condition() {
                    return localCondition.getAsBoolean();
                }
            }.sleep();


            // Sleep after the event is already true
            new ConditionalSleep(this.additionalDurationMs, 100) {
                @Override
                public boolean condition() {
                    return false;
                }
            }.sleep();

        }
        return true;
    }

}


here is one example from the main script: (immediately inside onLoop method)
for clarity:
V just stores variables like V.worldBank is an area
fatigueHandler is exactly what it sounds like - handles fatigue over time whilst playing which impacts the ms times it returns

The minimum value for getSleepTimeMs() is 41ms

However, clearly, from the script usage below, you can see that on bank.interact, it will either:


1) timeout after 5 seconds (in which case I haven't actually handled it yet)

2) succeed, in which case, it won't spam click anyway, since the bank will be open?

Neither of these two possibilities involve spam clicking?  Really appreciate any tips and advice on this
 

if(V.worldBank.contains(myPlayer().getPosition()) && state == StateEngine.State.BANKING) {
    if(!getBank().isOpen()){
        RS2Object bank = getNearestBank();
        if(!bank.exists()){
            log("Bank does not exist. Exiting.");
            onExit();
        }
        bank.interact("Bank");

        new CS(this, 5000, fatigueHandler.getSleepTimeMs(), () -> getBank().isOpen());

        getBank().depositAll();

        new CS(this, 3000, fatigueHandler.getShortSleepTimeMs(), () -> getInventory().isEmpty());

        getBank().withdraw("Adamant pickaxe", 1);

        new CS(this, 3000, fatigueHandler.getShortSleepTimeMs(), () -> getInventory().contains("Adamant pickaxe"));

        getBank().close();

        new CS(this, 3000, fatigueHandler.getShortSleepTimeMs(), () -> !getBank().isOpen());

        return 20;
    }
}

 

Off topic, but bonus if anyone knows; regards random events, is there a way to implement only some specific ones and ignore the others? It seems awfully bot-like to just ignore all of them, particularly the genie and the free stuff ones like rick terpentine - don't want to solve any stupid events, but I know if I am playing legit I will just talk to those ones to get free stuff, would like to emulate that

Link to comment
Share on other sites

Yeah that is basically the reason for it - for convenience I was hoping to make a more complex sleep so I can write (or copy-paste) less of my code

Since this doesn't seem to work, I am currently writing out the ConditionalSleep, then adding additional sleeps after, and writing the mouse offscreen code each time, which, given the amount of sleeps code tends to do, is annoying!

Trying to just call a single function that performs a sleep-cycle the way I want it to sleep - I can then make the function do things like consider fatigue  & high intensity play periods, mouse offscreen, and even occasionally AFK-log, only by writing a simple function call

I'm pretty new to Java tbh, it is not easy!

 

Link to comment
Share on other sites

1 hour ago, Fanny said:

Yeah that is basically the reason for it - for convenience I was hoping to make a more complex sleep so I can write (or copy-paste) less of my code

Since this doesn't seem to work, I am currently writing out the ConditionalSleep, then adding additional sleeps after, and writing the mouse offscreen code each time, which, given the amount of sleeps code tends to do, is annoying!

Trying to just call a single function that performs a sleep-cycle the way I want it to sleep - I can then make the function do things like consider fatigue  & high intensity play periods, mouse offscreen, and even occasionally AFK-log, only by writing a simple function call

I'm pretty new to Java tbh, it is not easy!

 

You can  add some log statements into your CS class to debug what is failing.

Alternatively do what you are currently doing with...
I am currently writing out the ConditionalSleep, then adding additional sleeps after, and writing the mouse offscreen code each time

but separate it out into a static utility method. I have this class that does something along the same lines. It just reattempts something up to n times as there can be race conditions with opening an interface, waiting for the interface actually becoming usable ingame, and attempting to interact with a widget in the interface. 

public class RetryUtil {
    public static boolean retry(Callable<Boolean> fx, int maxAttempts, int retryWaitTime) throws InterruptedException {
        int attempts = 0;
        boolean isSuccess = false;
        while (attempts < maxAttempts) {
            try {
                isSuccess = fx.call();
            } catch (Exception ignored) {
            }
            attempts++;
            if(isSuccess) {
                break;
            }
            MethodProvider.sleep(retryWaitTime);
        }
        return isSuccess;
    }


ex usage

RetryUtil.retry(() -> bank.withdraw(itemId, amount), 5, 1000)


You can try making something similar where you pass in a Callable that has some code you want to run (like bank.open()). Sleep until it is open, then  roll to sleep a bit more + move the mouse offscreen. 

Link to comment
Share on other sites

Posted (edited)
On 5/20/2024 at 5:27 AM, Fanny said:

Thanks! I think this is probably where I am getting stuck, static vs. non-static is a bit confusing to me still

I'll try adapting this to suit my use cases & let you know how I get on :)

Here's a link to help help explain the difference between static and non-static methods.

https://www.geeksforgeeks.org/difference-between-static-and-non-static-method-in-java/

Edited by BravoTaco
Link to comment
Share on other sites

On 5/20/2024 at 11:12 AM, yfoo said:

public class RetryUtil {

Thanks for sharing this - I genuinely hadn't thought of just looping with a short sleep, but this new approach, combined with understanding now static vs non-static has been extremely useful

It has also allowed me to add additional functionality into the loop itself

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...