Jump to content

Big Collection of Utilities!


Fanny

Recommended Posts

Just a collection of utility classes within org.fanny.utils

Hopefully this helps somebody get started, these make writing scripts super easy - see this example script:

Example Script (FannyGoldDigger) - Uses the generic utils methods and very short to write

Spoiler

FannyGoldDigger.java

Code:

package org.fanny.scripts.GoldDigger;

import org.fanny.utils.*;
import org.osbot.rs07.api.map.Area;
import org.osbot.rs07.script.ScriptManifest;
import org.osbot.rs07.script.Script;
import org.osbot.rs07.api.ui.Skill;
import org.osbot.rs07.api.ui.Message;

import java.awt.*;
import java.util.Arrays;

@ScriptManifest(
        name = "FannyGoldDigger",
        author = "Fanny",
        version = 1.0,
        info = "Mines gold at the crafting guild.",
        logo = ""
)
public class FannyGoldDigger extends Script {
    private static Tracker tracker;
    private static Miner miner;
    Area areaExact = new Area(2938, 3282, 2939, 3281);
    Area areaClick = new Area(2935, 3284, 2942, 3279);
    Area areaExtended = new Area(2934, 3293, 2945, 3273);

    @Override
    public final void onStart() {

        Utils.setMethodProvider(getBot().getMethods());
        tracker = new Tracker(
                "Fanny Gold Digger",
                Arrays.asList(Skill.MINING),
                Arrays.asList("Gold ore")
        );
        miner = new Miner(
                Arrays.asList("Gold ore"),
                areaExtended
        );
        log("'Starting up the shield!' ~ Some Gungan");
    }

    @Override
    public final int onLoop() throws InterruptedException {
        if (getInventory().isFull() || !inventory.contains("Rune pickaxe")) {
            if (getBank().isOpen()) {
                getBank().depositAll();
                Sleep.sleep(2000, () -> getInventory().isEmpty());
                return 20;
            } else {
                BankWalk.to(BankLocation.BANK_FALADOR_EAST);
                return 20;
            }
        } else if (inventory.isEmpty()) {
            if (getBank().isOpen()) {
                getBank().withdraw("Rune pickaxe", 1);
                Sleep.sleep(2000, () -> getInventory().contains("Rune pickaxe"));
                return 20;
            } else {
                BankWalk.to(BankLocation.BANK_FALADOR_EAST);
                return 20;
            }
        } else {
            if (areaExtended.contains(myPlayer().getPosition())) {
                miner.mine();
                return 20;
            }
            else{
                Walk.to(areaExact, areaClick, areaExtended);
                return 20;
            }
        }
    }


    @Override
    public final void onExit() {
        log("This will be printed to the logger when the script exits");
        getLogoutTab().logOut();
        stop();
    }

    @Override
    public final void onMessage(final Message message) {
        String oreMined = miner.updateRockCount(message.getMessage());
        tracker.updateItem(oreMined);
    }

    @Override
    public void onPaint(final Graphics2D g) {
        tracker.draw(g);
    }
}

 

 

Utils (for initialisation)

UtilsConfig & Utils.java

Spoiler

UtilsConfig.java

Usage:

Allows easy building of utils settings in the onStart() function

Code:

package org.fanny.utils;

/**
 * Configuration class for initializing the Utils class with optional parameters.
 * This class uses the Builder pattern to allow for flexible configuration of optional parameters.
 */
public final class UtilsConfig {
    private final boolean isHighIntensity;
    private final double fatigue;

    /**
     * Private constructor to prevent direct instantiation.
     *
     * @param builder the Builder object containing configuration settings
     */
    private UtilsConfig(Builder builder) {
        this.isHighIntensity = builder.isHighIntensity;
        this.fatigue = builder.fatigue;
    }

    /**
     * Gets the intensity configuration.
     *
     * @return true if high intensity, false otherwise
     */
    public boolean isHighIntensity() {
        return isHighIntensity;
    }

    /**
     * Gets the fatigue level.
     *
     * @return the fatigue level
     */
    public double getFatigue() {
        return fatigue;
    }


    /**
     * Builder class for creating instances of UtilsConfig.
     */
    public static final class Builder {
        private boolean isHighIntensity = false;
        private double fatigue = 0.0;


        /**
         * Sets the high intensity configuration.
         * This setting can be used to modify how certain utilities behave under high intensity conditions.
         *
         * @param isHighIntensity true to set the mode to high intensity, false otherwise
         * @return the Builder instance for chaining
         */
        public Builder setIsHighIntensity(boolean isHighIntensity) {
            this.isHighIntensity = isHighIntensity;
            return this;
        }

        /**
         * Sets the fatigue level configuration.
         * This value can affect calculations or thresholds in utility operations.
         *
         * @param fatigue the level of fatigue, should be a non-negative number
         * @return the Builder instance for chaining
         */
        public Builder setFatigue(double fatigue) {
            if (fatigue < 0) {
                throw new IllegalArgumentException("Fatigue cannot be negative.");
            }
            this.fatigue = fatigue;
            return this;
        }

        /**
         * Builds the UtilsConfig instance based on the builder's parameters.
         * This method ensures that the configuration is complete and consistent before use.
         *
         * @return a new UtilsConfig instance
         */
        public UtilsConfig build() {
            return new UtilsConfig(this);
        }
    }
}
Spoiler

Utils.java

Usage:

Set the intensity of the script which will control the sleep times. Also fatigue (so you can enter a script already fatigued). Intend to add more options in future, so the builder approach makes it much simpler to add them on the fly across all scripts without worrying about backwards compatibility when implementing new features.

// ALWAYS pass this in onStart(), this is the only critical piece of code
Utils.setMethodProvider(getBot().getMethods());


// Create a UtilsConfig instance using the Builder pattern
UtilsConfig config = new UtilsConfig.Builder()
    .setIsHighIntensity(true) // Enable high intensity mode
    .setFatigue(0.5)           // Set initial fatigue level to 0.5
    .build();

// Initialize the Utils class with the current MethodProvider and the configured UtilsConfig
Utils.init(getMethodProvider(), config);

Code:

package org.fanny.utils;

import org.osbot.rs07.script.MethodProvider;

import java.util.Random;

public final class Utils {

    private static MethodProvider methodProvider;
    private static boolean isHighIntensity = false;
    private static double fatigue = 0.0;
    private static double hash = 0.0;
    private static boolean isMouseOffScreen = false;

    /**
     * Initializes the Utils class with the provided MethodProvider and configuration.
     *
     * @param methodProvider the MethodProvider instance (mandatory)
     * @param config         the UtilsConfig object containing optional initialization parameters
     */
    public static void init(final MethodProvider methodProvider, final UtilsConfig config) {
        if (methodProvider == null) {
            throw new IllegalArgumentException("MethodProvider cannot be null.");
        }
        setMethodProvider(methodProvider);

        // Get username or generate a random one if it's null/empty
        String username = methodProvider.myPlayer().getName();
        if (username == null || username.isEmpty()) {
            username = generateRandomString(10);  // Generate a random string of length 10
        }
        Utils.hash = generateSeed(username);

        // Set the configuration
        if (config != null) {
            setIntensity(config.isHighIntensity());
            setFatigue(config.getFatigue());
            // Initialize additional fields from config
        }
    }


    /**
     * Sets the MethodProvider instance to be used by the Utils class.
     *
     * @param mp the MethodProvider instance
     */
    public static void setMethodProvider(final MethodProvider mp) {
        Utils.methodProvider = mp;
    }

    /**
     * Sets the intensity level.
     *
     * @param isHighIntensity true if high intensity is enabled, false otherwise
     */
    public static void setIntensity(final boolean isHighIntensity){
        Utils.isHighIntensity = isHighIntensity;
    }

    /**
     * Sets the fatigue level.
     *
     * @param level the fatigue level to set
     */
    public static void setFatigue(final double level) {
        Utils.fatigue = level;
    }

    /**
     * Sets whether the mouse is off-screen.
     *
     * @param isMouseOffScreen true if the mouse is off-screen, false otherwise
     */
    public static void setIsMouseOffScreen(final boolean isMouseOffScreen){
        Utils.isMouseOffScreen = isMouseOffScreen;
    }

    /**
     * Retrieves the MethodProvider instance.
     *
     * @return the MethodProvider instance
     * @throws IllegalStateException if the MethodProvider has not been set
     */
    public static MethodProvider getMethodProvider() {
        if (methodProvider == null) {
            throw new IllegalStateException("MethodProvider not set. Call Utils.setMethodProvider() before using utilities.");
        }
        return methodProvider;
    }

    /**
     * Retrieves the intensity level.
     *
     * @return true if high intensity is enabled, false otherwise
     */
    public static boolean getIntensity(){
        return Utils.isHighIntensity;
    }

    /**
     * Retrieves the fatigue level.
     *
     * @return the fatigue level
     */
    public static double getFatigue(){
        return Utils.fatigue;
    }

    /**
     * Retrieves the hash value generated from the username.
     *
     * @return the hash value
     */
    public static double getHash(){
        return Utils.hash;
    }

    /**
     * Checks if the mouse is off-screen.
     *
     * @return true if the mouse is off-screen, false otherwise
     */
    public static boolean getIsMouseOffScreen(){
        return Utils.isMouseOffScreen;
    }

    /**
     * Generates a random seed value between 0.9 and 1.4 based on the username's hash code.
     *
     * @param username the username to generate the seed from
     * @return a double value between 0.9 and 1.4
     */
    public static double generateSeed(final String username) {
        final int hashCode = username.hashCode();

        // Normalize hash code to a 0-1 range (assuming hashCode() can be any int value)
        final double normalized = (hashCode - (double) Integer.MIN_VALUE) / ((double) Integer.MAX_VALUE - (double) Integer.MIN_VALUE);

        // Scale and adjust the range to 0.9 to 1.4
        final double seed = 0.9 + (normalized * 0.5);  // 0.5 is the range size (1.4 - 0.9)

        return seed;
    }

    /**
     * Generates a random alphanumeric string of the specified length.
     *
     * @param length the length of the string to generate
     * @return a random alphanumeric string
     */
    private static String generateRandomString(final int length) {
        final String alphaNumericString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        final StringBuilder builder = new StringBuilder();
        final Random random = new Random();
        for (int i = 0; i < length; i++) {
            final int index = random.nextInt(alphaNumericString.length());
            builder.append(alphaNumericString.charAt(index));
        }
        return builder.toString();
    }
}

 

Sleep

Sleep.java

Spoiler

Sleep.java

Usage:

Really simple function that sleeps until an action completes, sometimes mouses out and waits after it has completed for a random time too. Really easy to use.

hasActionCompleted = Sleep.sleep(maxSleepTime, () -> checkCondition());

Code:

package org.fanny.utils;

import org.osbot.rs07.script.MethodProvider;

import java.util.Random;
import java.util.concurrent.Callable;

/**
 * Utility class for handling sleep operations with randomized behavior
 * and additional checks such as combat status and fatigue.
 */
public class Sleep {
    private static final Random RANDOM = new Random();

    /**
     * Executes a sleep operation with randomized timing and conditional behavior.
     * The method attempts to execute the provided Callable until it succeeds or
     * the maximum number of attempts is reached. It also incorporates logic to
     * handle mouse movement and adjusts sleep time based on various factors
     * such as combat status and fatigue.
     *
     * @param initialSleepTimeMs the initial sleep time in milliseconds
     * @param fx                 the Callable<Boolean> representing the action to execute
     * @return {@code true} if the action was successful, {@code false} otherwise
     * @throws InterruptedException if the thread is interrupted while sleeping
     */
    public static boolean sleep(final int initialSleepTimeMs, final Callable<Boolean> fx) throws InterruptedException {

        final MethodProvider methodProvider = Utils.getMethodProvider();
        final boolean isHighIntensity = Utils.getIntensity();
        final double fatigue = Utils.getFatigue();
        final double hash = Utils.getHash();

        // Check if in combat
        final boolean inCombat = methodProvider.myPlayer().isUnderAttack() || methodProvider.myPlayer().isHitBarVisible();

        final long startTime = System.currentTimeMillis();

        boolean isSuccess = false;

        int attempts = 0;
        int retryTimeMs = 25;
        final int durationMs = RANDOM.nextInt(400) + 50;
        int maxAttempts = durationMs / retryTimeMs;

        double sleepTime = 50.0;

        // Firstly wait a short time or until the action is complete
        while (attempts < maxAttempts) {
            try {
                isSuccess = fx.call();
            } catch (Exception ignored) {
            }
            attempts++;
            if (isSuccess) {
                break;
            }
            MethodProvider.sleep(retryTimeMs);
        }

        // After the short period, small chance to get bored & mouse out
        if (RANDOM.nextDouble() < 0.1) {
            methodProvider.getMouse().moveOutsideScreen();
            Utils.setIsMouseOffScreen(true);
        }

        // If not successful yet, continue checking with adjusted times
        if (!isSuccess) {
            double chanceToMoveMouseOffscreen = 0;
            attempts = 0;
            retryTimeMs = 50;
            maxAttempts = initialSleepTimeMs / retryTimeMs;

            if (inCombat) {
                retryTimeMs = 25;
                maxAttempts = (initialSleepTimeMs / 2) / retryTimeMs;
            }

            while (attempts < maxAttempts) {
                try {
                    isSuccess = fx.call();
                } catch (Exception ignored) {
                }
                attempts++;
                if (!Utils.getIsMouseOffScreen()) {
                    chanceToMoveMouseOffscreen += 0.001;
                    if (RANDOM.nextDouble() < chanceToMoveMouseOffscreen) {
                        methodProvider.getMouse().moveOutsideScreen();
                        Utils.setIsMouseOffScreen(true);
                    }
                }
                if (isSuccess) {
                    break;
                }
                MethodProvider.sleep(retryTimeMs);
            }
        }

        final long totalDuration = System.currentTimeMillis() - startTime;

        // Calculate sleep time with randomness based on username
        sleepTime = (
                (Math.log(totalDuration) / Math.log(2)) *
                        (RANDOM.nextInt(2) + 1) *
                        (RANDOM.nextInt(2) + 1) *
                        (RANDOM.nextInt(2) + 1) *
                        (RANDOM.nextInt(2) + 1) *
                        (RANDOM.nextInt(2) + 1) *
                        (RANDOM.nextInt(2) + 1) *
                        (RANDOM.nextInt(3) + 1) *
                        (RANDOM.nextInt(3) + 1) *
                        (RANDOM.nextInt(2) + 1) *
                        (RANDOM.nextInt(2) + 1) *
                        (RANDOM.nextInt(2) + 1)
        ) + 40;

        if(0.9 < hash && hash < 1.4) {
            sleepTime *= hash;
        }

        if(fatigue > 0){
            sleepTime *= (fatigue + 1);
        }

        // If the action took a while, more chance to sleep longer
        if (totalDuration > 5000) {
            long divided = totalDuration / 1000;
            if(divided > 20){
                divided = RANDOM.nextInt(20) + 1;
            }
            sleepTime *= (RANDOM.nextInt((int)divided) + 1);
        }

        // Reduce sleep time if in combat
        if (inCombat) {
            sleepTime /= 2;
        }

        if(isHighIntensity){
            Utils.setFatigue(fatigue + 0.1);
            sleepTime /= 2;
        }

        if(RANDOM.nextDouble() < 0.005){
            Utils.setFatigue(0.0);
        }

        MethodProvider.sleep((int) sleepTime);

        return isSuccess;
    }
}

 

 

Constants (for constants I use)

Const.java

Spoiler

Const.java

Usage:

I don't bother with fancy paint, so lines are separated using these constants. Also other generic constants such as exp level brackets.

Const.EXPERIENCES

Code:

package org.fanny.utils;

import java.awt.*;

public class Const {
    public static final int[] EXPERIENCES= {
            0, 0, 83, 174, 276, 388, 512, 650, 801, 969, 1154, 1358, 1584, 1833, 2107, 2411, 2746, 3115, 3523, 3973,
            4470, 5018, 5624, 6291, 7028, 7842, 8740, 9730, 10824, 12031, 13363, 14833, 16456, 18247, 20224, 22406,
            24815, 27473, 30408, 33648, 37224, 41171, 45529, 50339, 55649, 61512, 67983, 75127, 83014, 91721, 101333,
            111945, 123660, 136594, 150872, 166636, 184040, 203254, 224466, 247886, 273742, 302288, 333804, 368599,
            407015, 449428, 496254, 547953, 605032, 668051, 737627, 814445, 899257, 992895, 1096278, 1210421, 1336443,
            1475581, 1629200, 1798808, 1986068, 2192818, 2421087, 2673114, 2951373, 3258594, 3597792, 3972294, 4385776,
            4842295, 5346332, 5902831, 6517253, 7195629, 7944614, 8771558, 9684577, 10692629, 11805606, 13034431
    };

    public static final int paintStartX = 10;
    public static final int paintStartY = 40;
    public static final int paintLineHeight = 20;
    public static final Color paintTextColor = Color.white;
}

 

 

Tracker (easy paint)

Tracker.java

Spoiler

Tracker.java

Usage:

In the onStart() method you can set up the tracker to take parameters such as skills and items (for gathering / crafting)

// onStart()
tracker = new Tracker(
    "My Script Name",
    Arrays.asList(Skill.MINING, Skill.SMITHING),
    Arrays.asList("Gold ore", "Silver ore")
);

// Update methods (only updates 1 at a time)
tracker.updateItem("Gold ore");

// Make sure to set your onPaint() as follows:
@Override
public void onPaint(final Graphics2D g) {
    tracker.draw(g);
}

Code:

package org.fanny.utils;

import org.osbot.rs07.api.ui.Skill;
import org.osbot.rs07.script.MethodProvider;

import java.awt.*;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A generic Tracker class to monitor multiple skills' XP and item quantities.
 */
public class Tracker {
    private final MethodProvider methodProvider;
    private final Instant startTime;
    private final Map<Skill, Integer> startXP;

    // Map to store the count of each tracked item
    private final Map<String, Integer> itemsCollected;
    private final String scriptName;

    /**
     * Constructs a Tracker with specified skills and items to track.
     *
     * @param skillsToTrack List of skills to track XP for.
     * @param itemsToTrack  List of item names to track quantities.
     */
    public Tracker(String scriptName, List<Skill> skillsToTrack, List<String> itemsToTrack) {

        this.methodProvider = Utils.getMethodProvider();

        this.startTime = Instant.now();

        // Initialize maps
        this.startXP = new HashMap<>();
        this.itemsCollected = new HashMap<>();

        // Initialize skill trackers
        for (Skill skill : skillsToTrack) {
            int xp = methodProvider.getSkills().getExperience(skill);
            startXP.put(skill, xp);
        }

        // Initialize item trackers
        for (String item : itemsToTrack) {
            itemsCollected.put(item, 0);
        }
        this.scriptName = scriptName;
    }

    /**
     * Increments the count of a tracked item by 1.
     *
     * @param itemName The name of the item to update.
     */
    public void updateItem(String itemName) {
        if (itemsCollected.containsKey(itemName)) {
            itemsCollected.put(itemName, itemsCollected.get(itemName) + 1);
        } else {
            // Optionally, handle untracked items by initializing them
            itemsCollected.put(itemName, 1);
        }
    }

    /**
     * Retrieves the XP gained for a specific skill since tracking started.
     *
     * @param skill The skill to get XP gained for.
     * @return The XP gained.
     */
    public int gainedXP(Skill skill) {
        if (startXP.containsKey(skill)) {
            int currentXP = methodProvider.getSkills().getExperience(skill);
            return currentXP - startXP.get(skill);
        }
        return 0;
    }

    /**
     * Retrieves the XP gained per hour for a specific skill.
     *
     * @param skill The skill to get XP gained per hour for.
     * @return The XP gained per hour.
     */
    public double gainedPerHour(Skill skill) {
        Duration elapsed = Duration.between(startTime, Instant.now());
        double hours = elapsed.toMillis() / 3600000.0; // Convert milliseconds to hours

        if (hours > 0) {
            return gainedXP(skill) / hours;
        }
        return 0.0;
    }

    /**
     * Retrieves the current XP for a specific skill.
     *
     * @param skill The skill to get current XP for.
     * @return The current XP.
     */
    public int getCurrentXP(Skill skill) {
        return methodProvider.getSkills().getExperience(skill);
    }

    /**
     * Retrieves the starting XP for a specific skill.
     *
     * @param skill The skill to get starting XP for.
     * @return The starting XP.
     */
    public int getStartXP(Skill skill) {
        return startXP.getOrDefault(skill, 0);
    }

    /**
     * Retrieves the current level for a specific skill based on current XP.
     *
     * @param skill The skill to get current level for.
     * @return The current level.
     */
    public int getCurrentLevel(Skill skill) {
        int currentXP = getCurrentXP(skill);
        return getLevelAtExperience(currentXP);
    }

    /**
     * Retrieves the starting level for a specific skill based on starting XP.
     *
     * @param skill The skill to get starting level for.
     * @return The starting level.
     */
    public int getStartLevel(Skill skill) {
        int startingXP = getStartXP(skill);
        return getLevelAtExperience(startingXP);
    }

    /**
     * Retrieves the count of a specific tracked item.
     *
     * @param itemName The name of the item.
     * @return The count of the item collected.
     */
    public int getItemCount(String itemName) {
        return itemsCollected.getOrDefault(itemName, 0);
    }

    /**
     * Retrieves a map of all tracked items and their counts.
     *
     * @return A map of item names to counts.
     */
    public Map<String, Integer> getAllItemsCollected() {
        return new HashMap<>(itemsCollected);
    }

    /**
     * Retrieves a map of all tracked skills and their XP gained.
     *
     * @return A map of skills to XP gained.
     */
    public Map<Skill, Integer> getAllXPGained() {
        Map<Skill, Integer> xpGained = new HashMap<>();
        for (Skill skill : startXP.keySet()) {
            xpGained.put(skill, gainedXP(skill));
        }
        return xpGained;
    }

    /**
     * Calculates the level corresponding to a given experience.
     *
     * @param experience The experience points.
     * @return The level at the given experience.
     */
    public int getLevelAtExperience(int experience) {
        int index;

        for (index = 0; index < Const.EXPERIENCES.length - 1; index++) {
            if (Const.EXPERIENCES[index + 1] > experience)
                break;
        }

        return index;
    }

    /**
     * Retrieves the elapsed time since tracking started.
     *
     * @return A string representing the elapsed time in HH:MM:SS format.
     */
    public String getElapsedTime() {
        Duration elapsed = Duration.between(startTime, Instant.now());
        long hours = elapsed.toHours();
        long minutes = elapsed.toMinutes() % 60;
        long seconds = elapsed.getSeconds() % 60;
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }

    /**
     * Draws the tracking information on the screen.
     *
     * @param g The Graphics2D object used for drawing.
     */
    public void draw(Graphics2D g) {
        // Set the color for text
        g.setColor(Const.paintTextColor);

        int currentY = Const.paintStartY;

        // Draw Elapsed Time
        String elapsedTime = getElapsedTime();
        g.drawString(scriptName + ": " + elapsedTime, Const.paintStartX, currentY);
        currentY += Const.paintLineHeight;

        // Draw Items Collected
        StringBuilder itemsBuilder = new StringBuilder();
        for (Map.Entry<String, Integer> entry : itemsCollected.entrySet()) {
            itemsBuilder.append(entry.getKey()).append(": ").append(entry.getValue()).append(" | ");
        }
        String itemsDisplay = itemsBuilder.toString();
        if (itemsDisplay.endsWith(" | ")) {
            itemsDisplay = itemsDisplay.substring(0, itemsDisplay.length() - 3);
        }
        g.drawString(itemsDisplay, Const.paintStartX, currentY);
        currentY += Const.paintLineHeight;

        // Iterate over each tracked skill and display its statistics
        for (Skill skill : startXP.keySet()) {
            // XP Gained and Levels Gained
            int xpGained = gainedXP(skill);
            int startLevel = getStartLevel(skill);
            int currentLevel = getCurrentLevel(skill);
            int levelsGained = currentLevel - startLevel;
            String xpGainedStr = String.format("XP Gained (%s): %d (+%d levels)", skill.name(), xpGained, levelsGained);
            g.drawString(xpGainedStr, Const.paintStartX, currentY);
            currentY += Const.paintLineHeight;

            // XP per Hour
            double xpPerHour = gainedPerHour(skill);
            String xpPerHourStr = String.format("XP/Hour (%s): %.2f", skill.name(), xpPerHour);
            g.drawString(xpPerHourStr, Const.paintStartX, currentY);
            currentY += Const.paintLineHeight;

            // XP to Next Level
            int currentXP = getCurrentXP(skill);
            int xpToNextLevel = 0;
            if (currentLevel < Const.EXPERIENCES.length - 1) {
                xpToNextLevel = Const.EXPERIENCES[currentLevel + 1] - currentXP;
            } else {
                xpToNextLevel = 0; // Max level reached
            }
            String xpToNextLevelStr = String.format("XP to Level %d (%s): %d", currentLevel + 1, skill.name(), xpToNextLevel);
            g.drawString(xpToNextLevelStr, Const.paintStartX, currentY);
            currentY += Const.paintLineHeight;
        }
    }

}

 

Banking

BankLocation.java

Spoiler

BankLocation.java

Usage:

Stores (non-member only) bank locations with 3 overlapping areas for fine-tuned control

Code:

package org.fanny.utils;

import org.osbot.rs07.api.map.Area;

/**
 * Enum representing various bank locations with their corresponding areas.
 * Each bank location has three defined areas: exactArea, clickArea, and extendedArea.
 */
public enum BankLocation {
    BANK_AL_KHARID(
            new Area(3268, 3171, 3270, 3163), // Exact
            new Area(3268, 3174, 3273, 3163), // Click
            new Area(3262, 3177, 3278, 3158)  // Extended
    ),
    BANK_GRAND_EXCHANGE(
            new Area(3161, 3493, 3168, 3486),
            new Area(3157, 3493, 3172, 3482),
            new Area(3151, 3500, 3178, 3476)
    ),
    BANK_VARROCK_EAST(
            new Area(3251, 3420, 3255, 3419),
            new Area(3250, 3423, 3256, 3419),
            new Area(3244, 3430, 3263, 3412)
    ),
    BANK_VARROCK_WEST(
            new Area(3183, 3440, 3185, 3436),
            new Area(3180, 3442, 3186, 3433),
            new Area(3176, 3450, 3194, 3429)
    ),
    BANK_FALADOR_EAST(
            new Area(3009, 3356, 3016, 3355),
            new Area(3009, 3358, 3018, 3355),
            new Area(3006, 3361, 3025, 3350)
    ),
    BANK_FALADOR_WEST(
            new Area(2944, 3369, 2949, 3368),
            new Area(2943, 3373, 2947, 3368),
            new Area(2941, 3375, 2951, 3365)
    ),
    BANK_DRAYNOR(
            new Area(3091, 3245, 3092, 3241),
            new Area(3090, 3246, 3096, 3240),
            new Area(3085, 3248, 3100, 3238)
    ),
    BANK_EDGEVILLE_NORTH(
            new Area(3094, 3496, 3097, 3494),
            new Area(3091, 3499, 3098, 3494),
            new Area(3088, 3501, 3101, 3485)
    ),
    BANK_EDGEVILLE_SOUTH(
            new Area(3093, 3492, 3094, 3489),
            new Area(3091, 3494, 3094, 3488),
            new Area(3088, 3501, 3101, 3485)
    );

    private final Area exactArea;
    private final Area clickArea;
    private final Area extendedArea;

    /**
     * Constructs a BankLocation enum constant with specified areas.
     *
     * @param exactArea    the exact area of the bank location
     * @param clickArea    the area where clicks are detected or processed
     * @param extendedArea the extended area surrounding the bank location
     */
    BankLocation(Area exactArea, Area clickArea, Area extendedArea) {
        this.exactArea = exactArea;
        this.clickArea = clickArea;
        this.extendedArea = extendedArea;
    }

    // Getters
    public Area getExactArea() {
        return exactArea;
    }

    public Area getClickArea() {
        return clickArea;
    }

    public Area getExtendedArea() {
        return extendedArea;
    }
}

 

BankWalk.java

Spoiler

BankWalk.java

Usage:

Walks to the bank and opens the interface, returns true once the bank is open.

Bank.to(BankLocation.BANK_FALADOR_EAST);

Code:

package org.fanny.utils;

import org.osbot.rs07.api.map.Area;
import org.osbot.rs07.api.map.Position;
import org.osbot.rs07.script.MethodProvider;

import java.util.Random;

public final class BankWalk {
    private static final Random RANDOM = new Random();

    /**
     * Navigates the player to the specified bank location.
     * Attempts to walk to the bank's extended area and open the bank interface.
     *
     * @param bankLocation the {@link BankLocation} enum representing the target bank
     * @return {@code true} if the player successfully reached the bank and opened the bank interface,
     *         {@code false} otherwise
     * @throws InterruptedException if the thread is interrupted while sleeping
     */
    public static boolean to(BankLocation bankLocation) throws InterruptedException {

        final MethodProvider methodProvider = Utils.getMethodProvider();

        // Check if we're in the extended area
        int attempts = 0;
        boolean walked = false;
        while(attempts < 3 && !walked) {
            if (!bankLocation.getExtendedArea().contains(methodProvider.myPosition())) {
                Position destination = getRandomPositionNearExact(bankLocation.getExactArea(), bankLocation.getClickArea());
                // Walk to the extended area
                walked = methodProvider.getWalking().webWalk(destination);
                attempts++;
                Thread.sleep(RANDOM.nextInt(1950) + 50);
            }
            else{
                walked = true;
            }
        }

        if(!bankLocation.getExtendedArea().contains(methodProvider.myPosition())){
            methodProvider.log("Could not locate the bank.");
            return false;
        }

        // Open bank if not already open
        if (!methodProvider.getBank().isOpen()) {
            // Interact with bank booth or banker
            methodProvider.getBank().open();

            // Wait until bank is open
            if(!Sleep.sleep(5000, () -> methodProvider.getBank().isOpen())){
                methodProvider.getBank().open();
                return Sleep.sleep(5000, () -> methodProvider.getBank().isOpen());
            }
            else{
                return true;
            }
        }
        else{
            return true;
        }
    }

    /**
     * Calculates a random position near the exact area within the click area of the bank location.
     * This method ensures variability in the destination points to mimic human-like behavior.
     *
     * @param exactLocation the exact {@link Area} of the bank location
     * @param clickLocation the click {@link Area} of the bank location
     * @return a random {@link Position} within the click area near the exact location
     */
    private static Position getRandomPositionNearExact(Area exactLocation, Area clickLocation) {
        final Position exactCenter = exactLocation.getRandomPosition();
        final Position[] clickPositions = clickLocation.getPositions().toArray(new Position[0]);

        final double[] distances = new double[clickPositions.length];
        double totalWeight = 0;
        
        for (int i = 0; i < clickPositions.length; i++) {
            distances[i] = exactCenter.distance(clickPositions[i]);
            totalWeight += 1 / distances[i];
        }

        final double randomValue = RANDOM.nextDouble() * totalWeight;
        double cumulativeWeight = 0;
        
        for (int i = 0; i < clickPositions.length; i++) {
            cumulativeWeight += 1 / distances[i];
            if (randomValue <= cumulativeWeight) {
                return clickPositions[i];
            }
        }

        return clickLocation.getRandomPosition();
    }
}

 

Mining specific

Rock.java

Spoiler

Rock.java (NOT MINE, many thanks to @Explv)

Usage:

See original thread by @Explv

 

Code:

package org.fanny.utils;

import org.osbot.rs07.api.model.Entity;

/**
 * Enum representing different types of rocks (ores) in the game.
 * Each rock type has a display name and an array of color codes associated with it.
 * These color codes are used to identify the ore type based on the rock entity's appearance.
 */
public enum Rock {
    CLAY("Clay ore", new short[]{6705}),
    COPPER("Copper ore", new short[]{4645, 4510}),
    TIN("Tin ore", new short[]{53}),
    IRON("Iron ore", new short[]{2576}),
    SILVER("Silver ore", new short[]{74}),
    COAL("Coal", new short[]{10508}),
    GOLD("Gold ore", new short[]{8885}),
    MITHRIL("Mithril ore", new short[]{-22239}),
    ADAMANTITE("Adamantite ore", new short[]{21662}),
    RUNITE("Runite ore", new short[]{-31437});

    private final String displayName;
    private final short[] colours;

    /**
     * Constructs a Rock enum constant with the specified display name and color codes.
     *
     * @param displayName the display name of the ore (e.g., "Gold ore")
     * @param colours     the array of color codes associated with the ore
     */
    Rock(String displayName, short[] colours) {
        this.displayName = displayName;
        this.colours = colours;
    }

    public String getDisplayName() {
        return displayName;
    }

    /**
     * Determines if the given rock entity contains this ore type based on its colors.
     *
     * @param rockEntity The rock entity to check.
     * @return True if the rock contains this ore; otherwise, false.
     */
    public boolean hasOre(final Entity rockEntity) {
        if (rockEntity.getDefinition() == null) {
            return false;
        }

        final short[] entityColours = rockEntity.getDefinition().getModifiedModelColors();

        if (entityColours == null) {
            return false;
        }

        for (short rockColour : this.colours) {
            for (short entityColour : entityColours) {
                if (rockColour == entityColour) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Retrieves a Rock enum instance based on the provided ore name.
     *
     * @param oreName The name of the ore (e.g., "Gold ore").
     * @return The corresponding Rock enum, or null if no match is found.
     */
    public static Rock fromOreName(String oreName) {
        for (Rock rock : values()) {
            if (rock.getDisplayName().equalsIgnoreCase(oreName)) {
                return rock;
            }
        }
        return null;
    }
}

Miner.java

Spoiler

Miner.java

Usage:

Put this in the onStart() method, where areaExtended is the full mine area with a little overlap (maybe 7 squares)

// Put this in onStart()
miner = new Miner(
    Arrays.asList("Gold ore"),
    areaExtended
);

// Mining is now as easy as this:
miner.mine();

Code:

package org.fanny.utils;

import org.osbot.rs07.api.map.Area;
import org.osbot.rs07.api.map.Position;
import org.osbot.rs07.api.model.RS2Object;
import org.osbot.rs07.script.MethodProvider;

import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Objects;


public class Miner {
    private final MethodProvider methodProvider;
    private final List<String> oresToMine;
    private final List<Rock> rocksToMine;
    private final Area mineArea;
    private final Random random;

    /**
     * Constructs a Miner with specified parameters.
     *
     * @param oresToMine  List of ore names to mine.
     * @param mineArea    The Area object defining the mining zone.
     */
    public Miner(List<String> oresToMine, Area mineArea) {
        this.methodProvider = Utils.getMethodProvider();
        this.oresToMine = oresToMine;
        this.mineArea = mineArea;
        this.random = new Random();
        this.rocksToMine = mapOresToRocks(oresToMine);
    }

    /**
     * Maps a list of ore name strings to their corresponding Rock enums.
     *
     * @param oreNames List of ore names.
     * @return List of corresponding Rock enums.
     */
    private List<Rock> mapOresToRocks(List<String> oreNames) {
        return oreNames.stream()
                .map(Rock::fromOreName)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * Initiates the mining process.
     *
     * @throws InterruptedException If the script is interrupted during sleep.
     */
    public boolean mine() throws InterruptedException {
        if (mineArea.contains(methodProvider.myPlayer().getPosition())) {
            methodProvider.log("Finding the nearest rock with ore.");
            RS2Object rock = getClosestRockWithOre();
            if (rock == null) {
                methodProvider.log("No rocks with specified ores found.");
                return false;
            }

            Position rockPosition = rock.getPosition();
            if (!rock.exists()) {
                methodProvider.log("The rock does not exist. Exiting mining action.");
                return false;
            }

            rock.interact("Mine");
            methodProvider.log("Mining the rock.");

            Sleep.sleep(60000, () -> !checkRockHasOreAtPosition(rockPosition));
            return true;

        }
        return false;
    }

    /**
     * Finds the closest rock containing any of the specified ores.
     *
     * @return The closest RS2Object rock with ore, or null if none found.
     */
    private RS2Object getClosestRockWithOre() {
        List<RS2Object> rocksWithOre = methodProvider.getObjects().getAll()
                .stream()
                .filter(Objects::nonNull)
                .filter(obj -> rocksToMine.stream().anyMatch(rockType -> rockType.hasOre(obj)))
                .filter(this::noPlayerNearby)
                .filter(rock -> methodProvider.getMap().canReach(rock))
                .collect(Collectors.toList());

        if (rocksWithOre.isEmpty()) {
            return null;
        }

        // Find the closest rock
        RS2Object closestRock = methodProvider.getObjects().closest(rocksWithOre);

        // Check for multiple rocks within 1 square of the closest rock
        List<RS2Object> nearbyRocks = rocksWithOre.stream()
                .filter(rock -> rock.getPosition().distance(closestRock.getPosition()) <= 1)
                .collect(Collectors.toList());

        if (nearbyRocks.size() > 1) {
            return getPreferredRock(nearbyRocks);
        }

        return closestRock;
    }


    /**
     * Selects a preferred rock from a list of nearby rocks.
     *
     * @param rocks List of RS2Object rocks.
     * @return The preferred RS2Object rock.
     */
    private RS2Object getPreferredRock(List<RS2Object> rocks) {
        List<RS2Object> preferredRocks = rocks.stream()
                .filter(rock -> isDirectlyAdjacent(methodProvider.myPosition(), rock.getPosition()))
                .collect(Collectors.toList());

        if (!preferredRocks.isEmpty() && random.nextDouble() < 0.9) { // 90% preference
            return methodProvider.getObjects().closest(preferredRocks);
        }

        return methodProvider.getObjects().closest(rocks);
    }

    /**
     * Checks if two positions are directly adjacent (no diagonal).
     *
     * @param myPosition   The player's current position.
     * @param rockPosition The rock's position.
     * @return True if directly adjacent; otherwise, false.
     */
    private boolean isDirectlyAdjacent(Position myPosition, Position rockPosition) {
        int deltaX = rockPosition.getX() - myPosition.getX();
        int deltaY = rockPosition.getY() - myPosition.getY();

        return (deltaX == 0 && deltaY != 0) || (deltaY == 0 && deltaX != 0);
    }

    /**
     * Finds the closest rock from a list.
     *
     * @param rocks List of RS2Object rocks.
     * @return The closest RS2Object rock.
     */
    private RS2Object getClosest(List<RS2Object> rocks) {
        return rocks.stream()
                .min(Comparator.comparingInt(rock -> rock.getPosition().distance(methodProvider.myPosition())))
                .orElse(null);
    }

    /**
     * Checks if there are any players nearby the rock.
     *
     * @param rock The RS2Object rock.
     * @return True if no players are nearby; otherwise, false.
     */
    private boolean noPlayerNearby(RS2Object rock) {
        return methodProvider.getPlayers().closest(player ->
                player != null && !player.equals(methodProvider.myPlayer()) &&
                        player.getPosition().distance(rock.getPosition()) <= 1
        ) == null;
    }
    private boolean checkRockHasOreAtPosition(Position p) {
        RS2Object rock = methodProvider.getObjects().getAll()
                .stream()
                .filter(obj -> obj.getPosition().equals(p))
                .findFirst()
                .orElse(null);

        if (rock != null) {
            return rocksToMine.stream().anyMatch(rockType -> rockType.hasOre(rock));
        }
        return false;
    }


    public String updateRockCount(String msg){
        String oreMined = "";
        switch(msg){
            case "You manage to mine some copper.":
                oreMined = "Copper ore";
                break;
            case "You manage to mine some tin.":
                oreMined = "Tin ore";
                break;
            case "You manage to mine some iron.":
                oreMined = "Iron ore";
                break;
            case "You manage to mine some silver.":
                oreMined = "Silver ore";
                break;
            case "You manage to mine some coal.":
                oreMined = "Coal";
                break;
            case "You manage to mine some gold.":
                oreMined = "Gold ore";
                break;
            case "You manage to mine some mithril.":
                oreMined = "Mithril ore";
                break;
            case "You manage to mine some adamantite.":
                oreMined = "Adamantite ore";
                break;
            case "You manage to mine some runite.":
                oreMined = "Runite ore";
                break;
            case "You swing your pick at the rock.":
                // Ignore
                break;
            default:
                // TODO: Handle player messages
                break;
        }
        return oreMined;
    }

}

 

Walking

Walk.java

Spoiler

Walk.java

Usage:

To explain the areas, lets use smelting as an example.

areaExact = the 2 squares in front of the furnace

areaClick = the squares a player is likely to click on the map within this region (imagine you are lazily clicking to the location)

areaExtended = an area encompassing the entire building plus maybe 7 tiles all sides. (consider this to be "at destination")

Walk.to(areaExact, areaClick, areaExtended)

Code:

package org.fanny.utils;

import org.osbot.rs07.api.map.Area;
import org.osbot.rs07.api.map.Position;
import org.osbot.rs07.input.mouse.MiniMapTileDestination;
import org.osbot.rs07.script.MethodProvider;
import java.util.Random;

public final class Walk {
    private static final Random RANDOM = new Random();

    /**
     * Navigates the player to the specified location by walking to a target position.
     * Determines whether to perform a short walk or use web walking based on reachability and distance.
     *
     * @param exactLocation    the {@link Area} representing the exact location to walk to
     * @param clickLocation    the {@link Area} representing the clickable area near the exact location
     * @param extendedLocation the {@link Area} representing the extended area surrounding the exact location
     * @return {@code true} if the walk was successful, {@code false} otherwise
     * @throws InterruptedException if the thread is interrupted while sleeping
     */
    public static boolean to(final Area exactLocation, final Area clickLocation, final Area extendedLocation) throws InterruptedException {
        MethodProvider methodProvider = Utils.getMethodProvider();

        Position targetPosition = getRandomPositionNearExact(exactLocation, clickLocation);

        Walk.manageRunEnergy(methodProvider);

        if(methodProvider.getMap().canReach(targetPosition) && methodProvider.myPosition().distance(targetPosition) < 14){
            return shortWalk(methodProvider, targetPosition, extendedLocation);
        }
        else{
            return methodProvider.getWalking().webWalk(targetPosition);
        }
    }

    /**
     * Manages the player's run energy by potentially enabling running based on current run energy.
     * The higher the run energy, the higher the chance to turn on running.
     *
     * @param methodProvider the {@link MethodProvider} instance for accessing game methods
     * @throws InterruptedException if the thread is interrupted while sleeping
     */
    private static void manageRunEnergy(final MethodProvider methodProvider) throws InterruptedException {
        int runEnergy = methodProvider.getSettings().getRunEnergy();

        // Higher chance to turn on run the higher the run energy is
        if (!methodProvider.getSettings().isRunning() && RANDOM.nextInt(100) < runEnergy) {
            methodProvider.getSettings().setRunning(true);
            Sleep.sleep(500, () -> methodProvider.getSettings().isRunning());
            methodProvider.log("Run turned on with " + runEnergy + "% energy.");
        }
    }

    /**
     * Performs a short walk to the target position by clicking on the minimap and waiting until
     * the player reaches the extended location.
     *
     * @param methodProvider   the {@link MethodProvider} instance for accessing game methods
     * @param targetPosition   the {@link Position} to walk to
     * @param extendedLocation the {@link Area} representing the extended area to verify arrival
     * @return {@code true} if the player reached the extended location within the timeout, {@code false} otherwise
     * @throws InterruptedException if the thread is interrupted while sleeping
     */
    public static boolean shortWalk(final MethodProvider methodProvider, final Position targetPosition, final Area extendedLocation) throws InterruptedException {
        methodProvider.getMouse().click(new MiniMapTileDestination(methodProvider.getBot(), targetPosition, false));
        return Sleep.sleep(30000, () -> extendedLocation.contains(methodProvider.myPlayer().getPosition()));
    }

    /**
     * Calculates a random position near the exact location within the clickable area.
     * This method ensures variability in the destination points to mimic human-like behavior.
     *
     * @param exactLocation the exact {@link Area} of the target location
     * @param clickLocation the clickable {@link Area} near the exact location
     * @return a random {@link Position} within the clickable area near the exact location
     */
    private static Position getRandomPositionNearExact(final Area exactLocation, final Area clickLocation) {
        final Position exactCenter = exactLocation.getRandomPosition();
        final Position[] clickPositions = clickLocation.getPositions().toArray(new Position[0]);

        final double[] distances = new double[clickPositions.length];
        double totalWeight = 0;

        for (int i = 0; i < clickPositions.length; i++) {
            distances[i] = exactCenter.distance(clickPositions[i]);
            totalWeight += 1 / distances[i];
        }

        final double randomValue = RANDOM.nextDouble() * totalWeight;
        double cumulativeWeight = 0;

        for (int i = 0; i < clickPositions.length; i++) {
            cumulativeWeight += 1 / distances[i];
            if (randomValue <= cumulativeWeight) {
                return clickPositions[i];
            }
        }

        return clickLocation.getRandomPosition();
    }
}

 

 

Worlds / Hopping

World.java

Spoiler

World.java

Usage:

Just holds world variables, see Hopper.java

Code:

package org.fanny.utils;

import java.time.Instant;

public class World {
    private final int worldNumber;
    private final String region;
    private final boolean isMembers;
    private final boolean isPvP;
    private final String activity;
    private final String special;
    private final Integer skillTotal;
    private Instant nextAvailableTime;

    public World(int worldNumber, String region, boolean isMembers, boolean isPvP, String activity, String special, Integer skillTotal) {
        this.worldNumber = worldNumber;
        this.region = region.trim(); // Trim to remove any leading or trailing spaces
        this.isMembers = isMembers;
        this.isPvP = isPvP;
        this.activity = activity;
        this.special = special;
        this.skillTotal = skillTotal;
        this.nextAvailableTime = Instant.now();
    }


    // Getter methods
    public int getWorldNumber() {
        return worldNumber;
    }

    public String getRegion() {
        return region;
    }

    public boolean isMembers() {
        return isMembers;
    }

    public boolean isPvP() {
        return isPvP;
    }

    public String getActivity() {
        return activity;
    }

    public String getSpecial() {
        return special;
    }

    public Integer getSkillTotal() {
        return skillTotal;
    }

    public Instant getNextAvailableTime() {
        return nextAvailableTime;
    }

    public void setNextAvailableTime(long waitTimeInSeconds) {
        this.nextAvailableTime = Instant.now().plusSeconds(waitTimeInSeconds);
    }

    public boolean isAvailable() {
        return Instant.now().isAfter(nextAvailableTime);
    }
}

 

WorldManager.java

Spoiler

WorldManager.java

Usage:

This adds the whole list of worlds (current) with activity types etc. Utilises

See Hopper.java

Code:

package org.fanny.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class WorldManager {
    private List<World> worlds;

    public WorldManager() {
        worlds = new ArrayList<>();
        initializeWorlds();
    }

    private void initializeWorlds() {
        worlds.add(new World(301, "United States (east)", false, false, "Trade", "", 0));
        worlds.add(new World(302, "United Kingdom", true, false, "Trade", "", 0));
        worlds.add(new World(303, "Germany", true, false, "", "", 0));
        worlds.add(new World(304, "Germany", true, false, "Trouble Brewing", "", 0));
        worlds.add(new World(305, "United States (east)", true, false, "Falador Party Room", "", 0));
        worlds.add(new World(306, "United States (west)", true, false, "Barbarian Assault", "", 0));
        worlds.add(new World(307, "United States (west)", true, false, "Wintertodt", "", 0));
        worlds.add(new World(308, "United Kingdom", false, true, "PK", "", 0));
        worlds.add(new World(309, "United Kingdom", true, false, "Wintertodt", "", 0));
        worlds.add(new World(310, "United Kingdom", true, false, "Barbarian Assault", "", 0));
        worlds.add(new World(311, "Germany", true, false, "Wintertodt", "", 0));
        worlds.add(new World(312, "Germany", true, false, "Group Skilling", "", 0));
        worlds.add(new World(313, "United States (west)", true, false, "Group Skilling", "", 0));
        worlds.add(new World(314, "United States (east)", true, false, "Brimhaven Agility Arena", "", 0));
        worlds.add(new World(315, "United States (west)", true, false, "Fishing Trawler", "", 0));
        worlds.add(new World(316, "United Kingdom", false, true, "PK", "", 0));
        worlds.add(new World(317, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(318, "United Kingdom", true, true, "Bounty Hunter", "", 0));
        worlds.add(new World(320, "United States (west)", true, false, "Soul Wars", "", 0));
        worlds.add(new World(321, "United States (east)", true, false, "Sulliuscep cutting", "", 0));
        worlds.add(new World(322, "United States (east)", true, false, "Clan Wars - Free-for-all", "", 0));
        worlds.add(new World(323, "United States (west)", true, false, "Volcanic Mine", "", 0));
        worlds.add(new World(324, "United States (west)", true, false, "Group Iron", "", 0));
        worlds.add(new World(325, "United Kingdom", true, false, "Group Iron", "", 0));
        worlds.add(new World(326, "United Kingdom", false, false, "LMS Casual", "", 0));
        worlds.add(new World(327, "Germany", true, false, "Ourania Altar", "", 0));
        worlds.add(new World(328, "Germany", true, false, "Group Iron", "", 0));
        worlds.add(new World(329, "United States (east)", true, false, "Tombs of Amascut", "", 0));
        worlds.add(new World(330, "United States (east)", true, false, "House Party, Gilded Altar", "", 0));
        worlds.add(new World(331, "United States (west)", true, false, "Tombs of Amascut", "", 0));
        worlds.add(new World(332, "United States (west)", true, false, "Nex FFA", "", 0));
        worlds.add(new World(333, "United Kingdom", true, false, "Tombs of Amascut", "", 0));
        worlds.add(new World(334, "United Kingdom", true, false, "Castle Wars", "", 0));
        worlds.add(new World(335, "Germany", false, false, "Group Iron", "", 0));
        worlds.add(new World(336, "Germany", true, false, "ToA FFA", "", 0));
        worlds.add(new World(337, "United States (east)", true, false, "Nightmare of Ashihama", "", 0));
        worlds.add(new World(338, "United States (west)", true, false, "ToA FFA", "", 0));
        worlds.add(new World(339, "United States (west)", true, false, "", "", 0));
        worlds.add(new World(340, "United States (west)", true, false, "", "", 0));
        worlds.add(new World(341, "United Kingdom", true, false, "Tempoross", "", 0));
        worlds.add(new World(342, "United Kingdom", true, false, "Role-playing", "", 0));
        worlds.add(new World(343, "Germany", true, false, "", "", 0));
        worlds.add(new World(344, "Germany", true, false, "Pest Control", "", 0));
        worlds.add(new World(345, "United States (east)", true, false, "", "Deadman", 0));
        worlds.add(new World(346, "United States (east)", true, false, "Agility Training", "", 0));
        worlds.add(new World(347, "United States (west)", true, false, "", "", 0));
        worlds.add(new World(348, "United States (west)", true, false, "", "", 0));
        worlds.add(new World(349, "United Kingdom", true, false, "", "", 2000));
        worlds.add(new World(350, "United Kingdom", true, false, "Soul Wars", "", 0));
        worlds.add(new World(351, "Germany", true, false, "", "", 0));
        worlds.add(new World(352, "Germany", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(353, "United States (east)", true, false, "", "", 1250));
        worlds.add(new World(354, "United States (east)", true, false, "Castle Wars", "", 0));
        worlds.add(new World(355, "United States (west)", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(356, "United States (west)", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(357, "United States (west)", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(358, "United Kingdom", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(359, "Germany", true, false, "", "", 0));
        worlds.add(new World(360, "Germany", true, false, "", "", 0));
        worlds.add(new World(361, "United States (east)", true, false, "", "", 2000));
        worlds.add(new World(362, "United States (east)", true, false, "TzHaar Fight Pit", "", 0));
        worlds.add(new World(363, "United Kingdom", true, false, "", "", 2200));
        worlds.add(new World(364, "United Kingdom", true, false, "", "", 1250));
        worlds.add(new World(365, "United Kingdom", true, true, "High Risk", "", 0));
        worlds.add(new World(366, "United Kingdom", true, false, "", "", 1500));
        worlds.add(new World(367, "Germany", true, false, "", "", 0));
        worlds.add(new World(368, "Germany", true, false, "", "", 0));
        worlds.add(new World(369, "United States (east)", true, true, "PK", "", 0));
        worlds.add(new World(370, "United States (east)", true, false, "Fishing Trawler", "", 0));
        worlds.add(new World(371, "United Kingdom", false, false, "Group Iron", "", 0));
        worlds.add(new World(372, "United Kingdom", false, false, "", "", 750));
        worlds.add(new World(373, "United Kingdom", true, false, "", "", 1750));
        worlds.add(new World(374, "United States (west)", true, false, "Theatre of Blood", "", 0));
        worlds.add(new World(375, "Germany", true, false, "Zalcano", "", 0));
        worlds.add(new World(376, "Germany", true, false, "Theatre of Blood", "", 0));
        worlds.add(new World(377, "United States (east)", true, false, "Mort'ton Temple", "", 0));
        worlds.add(new World(378, "United States (west)", true, false, "Zalcano", "", 0));
        worlds.add(new World(379, "United Kingdom", false, false, "Arena", "", 0));
        worlds.add(new World(380, "United Kingdom", false, false, "", "", 0));
        worlds.add(new World(381, "United Kingdom", false, false, "", "", 500));
        worlds.add(new World(382, "United Kingdom", false, false, "", "", 0));
        worlds.add(new World(383, "Germany", false, false, "Castle Wars", "", 0));
        worlds.add(new World(384, "Germany", false, false, "", "", 0));
        worlds.add(new World(385, "United States (east)", true, false, "Brimhaven Agility", "", 0));
        worlds.add(new World(386, "United States (east)", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(387, "Australia", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(388, "Australia", true, false, "Forestry", "", 0));
        worlds.add(new World(389, "Australia", true, false, "Wintertodt", "", 0));
        worlds.add(new World(390, "Australia", true, false, "LMS Competitive", "", 0));
        worlds.add(new World(391, "Australia", true, false, "", "", 1750));
        worlds.add(new World(392, "Australia", true, true, "PK", "", 0));
        worlds.add(new World(393, "United States (east)", false, false, "", "", 750));
        worlds.add(new World(394, "United States (east)", false, false, "Clan Wars", "", 0));
        worlds.add(new World(395, "Germany", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(396, "Germany", true, false, "", "", 2000));
        worlds.add(new World(397, "Germany", false, false, "", "", 0));
        worlds.add(new World(398, "Germany", false, false, "Forestry", "", 0));
        worlds.add(new World(399, "Germany", false, false, "", "", 0));
        worlds.add(new World(413, "Germany", false, false, "", "", 500));
        worlds.add(new World(414, "Germany", false, false, "", "", 750));
        worlds.add(new World(415, "United States (east)", true, false, "", "", 2200));
        worlds.add(new World(416, "United States (east)", true, false, "", "", 1500));
        worlds.add(new World(417, "United States (east)", false, false, "Group Iron", "", 0));
        worlds.add(new World(418, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(419, "United States (west)", false, false, "", "", 500));
        worlds.add(new World(420, "United States (west)", true, false, "", "", 1500));
        worlds.add(new World(421, "United States (west)", true, false, "", "", 0));
        worlds.add(new World(422, "United States (west)", true, false, "Tempoross", "", 0));
        worlds.add(new World(423, "United States (west)", true, false, "", "Fresh Start", 0));
        worlds.add(new World(424, "Australia", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(425, "Australia", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(426, "Australia", true, false, "House Party", "", 0));
        worlds.add(new World(427, "Australia", false, false, "", "", 500));
        worlds.add(new World(428, "United States (west)", true, false, "", "", 2000));
        worlds.add(new World(429, "United States (west)", true, false, "", "", 1250));
        worlds.add(new World(430, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(431, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(432, "United States (west)", false, false, "", "", 750));
        worlds.add(new World(433, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(434, "United States (west)", false, false, "Forestry", "", 0));
        worlds.add(new World(435, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(436, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(437, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(441, "United States (west)", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(443, "United States (west)", true, false, "", "", 0));
        worlds.add(new World(444, "United States (west)", true, false, "Forestry", "", 0));
        worlds.add(new World(445, "United States (west)", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(446, "United States (west)", true, false, "Role-playing", "", 0));
        worlds.add(new World(447, "Germany", true, false, "", "", 1250));
        worlds.add(new World(448, "Germany", true, false, "", "", 1500));
        worlds.add(new World(449, "Germany", true, false, "", "", 1750));
        worlds.add(new World(450, "Germany", true, false, "", "", 2200));
        worlds.add(new World(451, "Germany", false, false, "", "", 0));
        worlds.add(new World(452, "Germany", false, false, "", "", 0));
        worlds.add(new World(453, "Germany", false, false, "", "", 0));
        worlds.add(new World(454, "Germany", false, false, "", "", 0));
        worlds.add(new World(455, "Germany", false, false, "", "", 0));
        worlds.add(new World(456, "Germany", false, false, "", "", 0));
        worlds.add(new World(459, "Germany", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(463, "Germany", true, false, "Tempoross", "", 0));
        worlds.add(new World(464, "Germany", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(465, "Germany", true, false, "House Party", "", 0));
        worlds.add(new World(466, "Germany", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(467, "United States (east)", true, false, "", "", 1750));
        worlds.add(new World(468, "United States (east)", false, false, "", "", 500));
        worlds.add(new World(469, "United States (east)", false, false, "LMS Casual", "", 0));
        worlds.add(new World(474, "United States (east)", true, true, "High Risk", "", 0));
        worlds.add(new World(475, "United States (east)", false, false, "", "", 0));
        worlds.add(new World(476, "United States (east)", false, false, "", "", 0));
        worlds.add(new World(477, "United States (east)", true, false, "Clan Recruitment", "", 0));
        worlds.add(new World(478, "United States (east)", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(479, "United States (east)", true, false, "Arena", "", 0));
        worlds.add(new World(480, "United States (east)", true, false, "Ourania Altar", "", 0));
        worlds.add(new World(481, "United States (east)", true, false, "Nex FFA", "", 0));
        worlds.add(new World(482, "United States (east)", true, false, "", "", 0));
        worlds.add(new World(483, "United States (east)", false, false, "", "", 0));
        worlds.add(new World(484, "United States (east)", true, false, "", "", 0));
        worlds.add(new World(485, "United States (east)", true, false, "", "", 0));
        worlds.add(new World(486, "United States (east)", true, false, "", "", 0));
        worlds.add(new World(487, "United States (east)", true, false, "Forestry", "", 0));
        worlds.add(new World(488, "United States (east)", true, false, "", "", 0));
        worlds.add(new World(489, "United States (east)", true, false, "", "", 0));
        worlds.add(new World(490, "United States (east)", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(491, "United States (east)", true, false, "Burthorpe Games Room", "", 0));
        worlds.add(new World(492, "United States (east)", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(493, "United States (east)", true, false, "Pyramid Plunder", "", 0));
        worlds.add(new World(494, "United States (east)", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(495, "United States (east)", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(496, "United States (east)", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(497, "United Kingdom", false, false, "Clan Recruitment", "", 0));
        worlds.add(new World(498, "United Kingdom", false, false, "", "", 0));
        worlds.add(new World(499, "United Kingdom", false, false, "", "", 0));
        worlds.add(new World(500, "United Kingdom", false, false, "", "", 0));
        worlds.add(new World(501, "United Kingdom", false, false, "", "", 0));
        worlds.add(new World(502, "United Kingdom", true, false, "", "Speedrun", 0));
        worlds.add(new World(505, "United Kingdom", true, false, "Nex FFA", "", 0));
        worlds.add(new World(506, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(507, "United Kingdom", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(508, "United Kingdom", true, false, "Brimhaven Agility", "", 0));
        worlds.add(new World(509, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(510, "United Kingdom", true, false, "Forestry", "", 0));
        worlds.add(new World(511, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(512, "United Kingdom", true, false, "House Party, Gilded Altar", "", 0));
        worlds.add(new World(513, "United Kingdom", true, false, "Zeah Runecrafting", "", 0));
        worlds.add(new World(514, "United Kingdom", true, false, "Nightmare of Ashihama", "", 0));
        worlds.add(new World(515, "United Kingdom", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(516, "United Kingdom", true, false, "Blast Furnace", "", 0));
        worlds.add(new World(517, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(518, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(519, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(520, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(521, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(522, "United Kingdom", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(523, "United Kingdom", true, false, "Nex FFA", "", 0));
        worlds.add(new World(524, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(525, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(526, "Australia", true, false, "", "", 2200));
        worlds.add(new World(527, "Australia", true, false, "", "", 2000));
        worlds.add(new World(528, "Australia", true, false, "", "", 1500));
        worlds.add(new World(529, "Australia", true, false, "", "", 1250));
        worlds.add(new World(530, "Australia", false, false, "", "", 750));
        worlds.add(new World(531, "Australia", true, false, "Tombs of Amascut", "", 0));
        worlds.add(new World(532, "Australia", true, false, "Group PvM", "", 0));
        worlds.add(new World(533, "Australia", true, true, "High Risk", "", 0));
        worlds.add(new World(534, "Australia", true, false, "Guardians of the Rift", "", 0));
        worlds.add(new World(535, "Australia", true, false, "Soul Wars", "", 0));
        worlds.add(new World(537, "Australia", false, false, "", "", 0));
        worlds.add(new World(539, "United States (east)", true, true, "PvP", "", 0));
        worlds.add(new World(540, "United States (west)", true, false, "", "Speedrun", 0));
        worlds.add(new World(544, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(545, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(546, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(547, "United States (west)", false, false, "", "", 0));
        worlds.add(new World(548, "Germany", true, true, "High Risk", "", 0));
        worlds.add(new World(549, "Germany", true, false, "", "Speedrun", 0));
        worlds.add(new World(552, "Germany", false, false, "", "", 0));
        worlds.add(new World(553, "Germany", false, false, "", "", 0));
        worlds.add(new World(554, "Germany", false, false, "", "", 0));
        worlds.add(new World(555, "Germany", false, false, "", "", 0));
        worlds.add(new World(558, "United Kingdom", true, false, "Arena", "", 0));
        worlds.add(new World(559, "United Kingdom", true, false, "LMS Competitive", "", 0));
        worlds.add(new World(565, "United Kingdom", false, false, "", "Fresh Start", 0));
        worlds.add(new World(567, "United Kingdom", true, false, "", "", 0));
        worlds.add(new World(568, "Australia", true, false, "", "Speedrun", 0));
        worlds.add(new World(569, "Australia", true, true, "Bounty Hunter", "", 0));
        worlds.add(new World(570, "Australia", true, false, "Arena", "", 0));
        worlds.add(new World(571, "Australia", false, false, "", "", 0));
        worlds.add(new World(573, "United States (east)", true, true, "Bounty Hunter", "", 0));
        worlds.add(new World(575, "United States (east)", false, false, "", "", 0));
        worlds.add(new World(576, "United States (east)", true, false, "", "Speedrun", 0));
        worlds.add(new World(577, "United States (east)", false, true, "PvP", "", 0));
        worlds.add(new World(578, "United States (east)", true, false, "Arena", "", 0));
    }

    // Existing methods remain unchanged
    public List<World> filterWorlds(WorldFilter filter) {
        return worlds.stream()
                .filter(world -> !filter.isPvP() || world.isPvP())
                .filter(world -> filter.getSpecial().isEmpty() || world.getSpecial().equals(filter.getSpecial()))
                .filter(world -> filter.isF2P() == !world.isMembers())
                .filter(world -> filter.getSkillTotal() == null || (world.getSkillTotal() != null && world.getSkillTotal() >= filter.getSkillTotal()))
                .filter(world -> filter.getRegion() == null || world.getRegion().equalsIgnoreCase(filter.getRegion()))
                .filter(world -> filter.getActivity() == null || world.getActivity().equalsIgnoreCase(filter.getActivity()))
                .filter(world -> world.isAvailable())
                .collect(Collectors.toList());
    }

    /**
     * Update the timer for a world to be available after a certain period.
     * @param worldId The world ID to update.
     * @param waitTimeInSeconds The wait time in seconds before the world can be used again.
     */
    public void updateWorldTimer(int worldId, long waitTimeInSeconds) {
        for (World world : worlds) {
            if (world.getWorldNumber() == worldId) {
                world.setNextAvailableTime(waitTimeInSeconds);
                System.out.println("Updated world " + worldId + " to be available after " + waitTimeInSeconds + " seconds.");
                break;
            }
        }
    }
}

 

WorldFilter.java

Spoiler

WorldFilter.java

Usage:

See Hopper.java

Code:

package org.fanny.utils;

public class WorldFilter {
    private boolean isPvP = false;
    private String special = ""; // Now a string to match against
    private boolean isF2P = true;
    private Integer skillTotal = null; // Now an Integer, can be null to represent no filter
    private String region = null; // Optional filter for region
    private String activity = null; // Optional filter for activity

    private WorldFilter(Builder builder) {
        this.isPvP = builder.isPvP;
        this.special = builder.special;
        this.isF2P = builder.isF2P;
        this.skillTotal = builder.skillTotal;
        this.region = builder.region;
        this.activity = builder.activity;
    }

    public static class Builder {
        private boolean isPvP = false;
        private String special = "";
        private boolean isF2P = true;
        private Integer skillTotal = null;
        private String region = null;
        private String activity = null;

        public Builder setPvP(boolean isPvP) {
            this.isPvP = isPvP;
            return this;
        }

        public Builder setSpecial(String special) {
            this.special = special;
            return this;
        }

        public Builder setF2P(boolean isF2P) {
            this.isF2P = isF2P;
            return this;
        }

        public Builder setSkillTotal(Integer skillTotal) {
            this.skillTotal = skillTotal;
            return this;
        }

        public Builder setRegion(String region) {
            this.region = region;
            return this;
        }

        public Builder setActivity(String activity) {
            this.activity = activity;
            return this;
        }

        public WorldFilter build() {
            return new WorldFilter(this);
        }
    }

    // Getters for each field
    public boolean isPvP() { return isPvP; }
    public String getSpecial() { return special; }
    public boolean isF2P() { return isF2P; }
    public Integer getSkillTotal() { return skillTotal; }
    public String getRegion() { return region; }
    public String getActivity() { return activity; }
}

 

Hopper.java

Spoiler

Hopper.java

Usage:

Hops worlds using Hopper.hop(), not 100% sure this worlds as intended as it is untested, but should work and makes it easy for you to use in scripts

// Put this in onStart()
hopper = new Hopper(worldManager);

// Define filtering criteria using WorldFilter.Builder
WorldFilter filter = new WorldFilter.Builder()
    .setPvP(true)                // Filter for PvP-enabled worlds
    .setF2P(false)               // Filter for Members-only worlds
    .setRegion("Germany")        // Filter for worlds located in Germany
    .setActivity("Blast Furnace")// Filter for worlds with the "Blast Furnace" activity
    .build();

// Initialize Hopper with the specified filter
hopper.initWorlds(filter);


// Later you can use this in the script:
Hopper.hop();

Code:

package org.fanny.utils;

import org.osbot.rs07.script.MethodProvider;

import java.util.List;

public class Hopper {
    private final MethodProvider methodProvider;
    private final WorldManager worldManager;
    private List<World> filteredWorlds;
    private int currentIndex = 0;
    private WorldFilter currentFilter;

    public Hopper(WorldManager worldManager) {
        this.methodProvider = Utils.getMethodProvider();
        this.worldManager = worldManager;
    }

    /**
     * Initialize the world list based on the specified filter.
     * @param filter The world filter settings.
     */
    public void initWorlds(WorldFilter filter) {
        filteredWorlds = worldManager.filterWorlds(filter);
        currentIndex = 0; // Reset index whenever filter is applied
    }

    public boolean hop() throws InterruptedException {
        if (filteredWorlds.isEmpty()) {
            System.out.println("No worlds available to hop.");
            return false;
        }
        World nextWorld = filteredWorlds.get(currentIndex);
        currentIndex = (currentIndex + 1) % filteredWorlds.size(); // Loop back to start
        System.out.println("Hopping to world: " + nextWorld.getWorldNumber());
        // Add your code here to perform the actual world hop
        // Assuming hop method returns a boolean indicating success
        return performWorldHop(nextWorld);
    }

    private boolean performWorldHop(World world) throws InterruptedException {
        methodProvider.getWorlds().hop(world.getWorldNumber());
        boolean isInWorld = Sleep.sleep(5000, () -> methodProvider.getWorlds().getCurrentWorld() ==  world.getWorldNumber());

        if(!isInWorld){
            methodProvider.getWorlds().hop(world.getWorldNumber());
            isInWorld = Sleep.sleep(5000, () -> methodProvider.getWorlds().getCurrentWorld() ==  world.getWorldNumber());
        }

        if(!isInWorld){
            return false;
        }
        // Return true if hop is successful, false otherwise
        System.out.println("Hopped to world: " + world.getWorldNumber());
        return true; // Modify as needed based on actual hop method success
    }


    public void timer(int worldId, long waitTimeInSeconds) {
        worldManager.updateWorldTimer(worldId, waitTimeInSeconds);
    }

    /**
     * Initialize or update the world list based on the specified filter.
     * @param filter The world filter settings.
     */
    public void updateFilterAndWorlds(WorldFilter filter) {
        this.currentFilter = filter;  // Save the filter for potential future updates
        this.filteredWorlds = worldManager.filterWorlds(filter);
        this.currentIndex = 0; // Reset index whenever filter is reapplied
        System.out.println("Filter updated and worlds reinitialized.");
    }
}

 

Edited by Fanny
  • Like 1
Link to comment
Share on other sites

  • Fanny changed the title to Big Collection of Utilities!

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...