Jump to content

[Open Source] Dubai's OakBurner [BETA]


dubai

Recommended Posts

Dubai's OakBurner [BETA]

Chop and Burn any Oak Tree!

Start this script next to an Oak Tree with your axe equipped or in your inventory with a tinderbox.

The script will chop a full inventory of oak logs, and burn them before returning back to the starting tree.

(It might wander off while it's firemaking(It handles "You can't light a fire here" and moves to a new spot to keep lighting fires) But the script will return to the starting tree after burning.

Nice and simple Onscreen Paint tracking Runtime and XP/LVLs gained.


Oak-Burner10minutes.png

 

Need some testers on this, I've ran for over an hour without issues, just moving on to other things. If you encounter bugs/crashes please try and screenshot the issue and provide as much info as you can and I'll return to this project for fixes. I've been running it south/west falador and it works really well over 20k FM xp/hr depending on your axe. The bot seems really smooth, especially firemaking.

 

DOWNLOAD: (EXTRACT TO YOUR "OSBOT/SCRIPTS/" PATH)

If anyone could upload some screenshots of nice runtimes, that would be awesome!

Source:

Spoiler
import org.osbot.rs07.api.map.Position;
import org.osbot.rs07.api.model.Entity;
import org.osbot.rs07.api.ui.Skill;
import org.osbot.rs07.canvas.paint.Painter;
import org.osbot.rs07.listener.MessageListener;
import org.osbot.rs07.script.Script;
import org.osbot.rs07.script.ScriptManifest;
import org.osbot.rs07.utility.ConditionalSleep;
import org.osbot.rs07.api.ui.Message;
import java.util.HashSet;
import java.util.Set;
import java.awt.*;

    @ScriptManifest(author = "Dubai", info = "Burn any oak tree!", name = "OakBurner", version = 1, logo = "")
    public class OakBurner extends Script implements MessageListener, Painter {

        private static final int OAK_TREE_ID = 10820;
        private boolean fireLit = false;
        private int moveRetryCount = 0;
        private static final int MAX_RETRY_COUNT = 3;

        // Paint-related variables
        private long startTime;
        private int startingWoodcuttingLevel;
        private int startingFiremakingLevel;
        private int startingWoodcuttingXP;
        private int startingFiremakingXP;
        private boolean shouldMoveToSafeSpot = false;

        private Position startingPosition; // Save the starting position

        private enum State {
            CHOPPING, LIGHTING_FIRES, MOVING_TO_SAFE_SPOT, RETURNING_TO_START
        }

        private State currentState = State.CHOPPING;

        @Override
        public void onStart() {
            getBot().addMessageListener(this);

            // Save the starting position
            startingPosition = myPosition();

            // Initialize paint-related variables
            startTime = System.currentTimeMillis();
            startingWoodcuttingLevel = skills.getStatic(Skill.WOODCUTTING);
            startingFiremakingLevel = skills.getStatic(Skill.FIREMAKING);
            startingWoodcuttingXP = skills.getExperience(Skill.WOODCUTTING);
            startingFiremakingXP = skills.getExperience(Skill.FIREMAKING);
        }

        @Override
        public void onExit() {
            getBot().removeMessageListener(this);
        }

        @Override
        public int onLoop() throws InterruptedException {
            log("Current State: " + currentState);

            switch (currentState) {
                case CHOPPING:
                    chopOakTree();
                    break;
                case LIGHTING_FIRES:
                    lightFires();
                    break;
                case MOVING_TO_SAFE_SPOT:
                    moveToSafeSpot();
                    break;
                case RETURNING_TO_START:
                    returnToStart();
                    break;
            }
            return random(200, 300);
        }

        private void chopOakTree() {
            log("State: CHOPPING");
            if (inventory.isFull()) {
                log("Inventory full, switching to LIGHTING_FIRES state.");
                currentState = State.LIGHTING_FIRES;
                return;
            }

            Entity oakTree = getObjects().closest(OAK_TREE_ID);
            if (oakTree != null && oakTree.interact("Chop down")) {
                log("Chopping Oak tree at: " + oakTree.getPosition());
                waitUntilNotAnimating();
                if (!inventory.isFull()) {
                    log("Finished chopping. Inventory not full. Retrying CHOPPING state.");
                    chopOakTree();  // Retry chopping if inventory isn't full
                } else {
                    log("Inventory full, switching to LIGHTING_FIRES state.");
                    currentState = State.LIGHTING_FIRES;
                }
            } else {
                log("No Oak tree found or failed to interact.");
            }
        }

        private void lightFires() throws InterruptedException {
            log("State: LIGHTING_FIRES");

            // Check if the bot should move based on the chat message
            if (shouldMoveToSafeSpot) {
                log("Should move to a safe spot due to chat message.");
                currentState = State.MOVING_TO_SAFE_SPOT;
                shouldMoveToSafeSpot = false;  // Reset the flag after setting the state
                return;
            }

            if (!inventory.contains("Oak logs")) {
                log("No Oak logs left. Switching to RETURNING_TO_START state.");
                currentState = State.RETURNING_TO_START;
                return;
            }

            if (inventory.contains("Tinderbox") && inventory.contains("Oak logs")) {
                log("Using Tinderbox on Oak logs.");
                if (inventory.getItem("Tinderbox").interact("Use")) {
                    new ConditionalSleep(1000) {
                        @Override
                        public boolean condition() {
                            return inventory.isItemSelected();
                        }
                    }.sleep();

                    if (inventory.isItemSelected()) {
                        if (inventory.getItem("Oak logs").interact("Use")) {
                            log("Using Oak logs.");
                            new ConditionalSleep(3000) {
                                @Override
                                public boolean condition() {
                                    return myPlayer().isAnimating();
                                }
                            }.sleep();

                            if (myPlayer().isAnimating()) {
                                log("Player is animating, waiting for fire to be lit.");
                                new ConditionalSleep(5000) {
                                    @Override
                                    public boolean condition() {
                                        return !myPlayer().isAnimating();
                                    }
                                }.sleep();

                                if (fireLit) {
                                    log("Fire lit successfully. Continuing to light more fires.");
                                    fireLit = false;
                                    lightFires();
                                } else if (shouldMoveToSafeSpot) {  // Double-check before retrying
                                    log("Detected 'You can't light a fire here.' while animating. Switching to MOVING_TO_SAFE_SPOT state.");
                                    currentState = State.MOVING_TO_SAFE_SPOT;
                                    shouldMoveToSafeSpot = false;
                                } else {
                                    log("Retrying lighting fires.");
                                    lightFires();
                                }
                            } else {
                                log("Failed to start lighting logs, retrying.");
                                lightFires();
                            }
                        } else {
                            log("Failed to interact with Oak logs.");
                        }
                    } else {
                        log("Failed to select Tinderbox.");
                    }
                } else {
                    log("Failed to use Tinderbox.");
                }
            } else {
                log("Tinderbox or Oak logs not found in inventory.");
            }
        }

        private Set<Position> attemptedSafeSpots = new HashSet<>();

        private void moveToSafeSpot() throws InterruptedException {
            log("State: MOVING_TO_SAFE_SPOT");
            Position safeSpot = findSafeSpot(3, 6);
            if (safeSpot == null || safeSpot.equals(myPosition())) {
                log("No suitable safe spot found. Expanding search area.");
                safeSpot = findSafeSpot(6, 10);
            }

            if (safeSpot != null && !safeSpot.equals(myPosition())) {
                log("Moving to safe spot at: " + safeSpot);
                attemptedSafeSpots.add(safeSpot); // Add the safe spot to the attempted list
                if (getWalking().webWalk(safeSpot)) { // Use webWalk instead of walk
                    Position finalSafeSpot = safeSpot;
                    new ConditionalSleep(7000) {
                        @Override
                        public boolean condition() {
                            return myPlayer().getPosition().equals(finalSafeSpot);
                        }
                    }.sleep();
                    if (myPlayer().getPosition().equals(finalSafeSpot)) {
                        log("Arrived at the safe spot. Switching to LIGHTING_FIRES state.");
                        currentState = State.LIGHTING_FIRES;
                        moveRetryCount = 0;
                        lightFires(); // Call the lightFires method to start lighting fires again
                    } else {
                        log("Failed to reach the safe spot. Retrying.");
                        retryMovement();
                    }
                } else {
                    log("Failed to initiate webWalk. Retrying.");
                    retryMovement();
                }
            } else {
                log("Failed to find a safe spot. Retrying.");
                retryMovement();
            }
        }

        private void retryMovement() throws InterruptedException {
            log("Failed to move to the safe spot. Retrying.");
            moveRetryCount++;
            if (moveRetryCount >= MAX_RETRY_COUNT) {
                log("Max retry count reached, returning to starting location.");
                currentState = State.RETURNING_TO_START;
                moveRetryCount = 0;
            } else {
                moveToSafeSpot();
            }
        }

        private void waitUntilNotAnimating() {
            new ConditionalSleep(5000) {
                @Override
                public boolean condition() {
                    return !myPlayer().isAnimating();
                }
            }.sleep();
        }

        private boolean useItem(String itemName) {
            return inventory.getItem(itemName).interact("Use");
        }

        private Position getSafeSpot() {
            return findSafeSpot(3, 6);
        }

        private Position getSafeSpotFarther() {
            return findSafeSpot(6, 10);
        }

        private Position findSafeSpot(int minRadius, int maxRadius) {
            for (int radius = minRadius; radius <= maxRadius; radius++) {
                for (int x = -radius; x <= radius; x++) {
                    for (int y = -radius; y <= radius; y++) {
                        Position pos = myPosition().translate(x, y);
                        if (!pos.equals(myPosition()) && getMap().canReach(pos) && !isFireNearby(pos) && !attemptedSafeSpots.contains(pos)) {
                            log("Found safe spot: " + pos);
                            return pos;
                        }
                    }
                }
            }
            log("No safe spot found within radius.");
            return null;
        }

        private boolean isFireNearby(Position pos) {
            return getObjects().closest(obj -> obj != null && obj.getName().equals("Fire") && obj.getPosition().equals(pos)) != null;
        }

        private void returnToStart() {
            log("State: RETURNING_TO_START");
            if (getWalking().webWalk(startingPosition)) {
                new ConditionalSleep(7000) {
                    @Override
                    public boolean condition() {
                        return myPlayer().getPosition().equals(startingPosition);
                    }
                }.sleep();
                if (myPlayer().getPosition().equals(startingPosition)) {
                    log("Returned to starting position. Switching to CHOPPING state.");
                    currentState = State.CHOPPING;
                } else {
                    log("Failed to return to starting position. Retrying.");
                    retryReturnToStart();
                }
            } else {
                log("Failed to initiate webWalk to starting position. Retrying.");
                retryReturnToStart();
            }
        }

        private void retryReturnToStart() {
            log("Retrying return to starting position.");
            moveRetryCount++;
            if (moveRetryCount >= MAX_RETRY_COUNT) {
                log("Max retry count reached. Switching to CHOPPING state.");
                currentState = State.CHOPPING;
                moveRetryCount = 0;
            } else {
                returnToStart();
            }
        }

        @Override
        public void onMessage(Message message) throws InterruptedException {
            log("Received message: " + message.getMessage());
            if (message.getType() == Message.MessageType.GAME) {
                if (message.getMessage().contains("The fire catches and the logs begin to burn.") ||
                        message.getMessage().matches(".*logs begin to burn.*")) {
                    log("Detected fire lit message.");
                    fireLit = true;
                } else if (message.getMessage().contains("You can't light a fire here.")) {
                    log("Detected 'You can't light a fire here.' message.");
                    shouldMoveToSafeSpot = true;  // Set the flag to indicate movement is needed
                }
            }
        }

        @Override
        public void onPaint(Graphics2D g) {
            long runTime = System.currentTimeMillis() - startTime;

            int currentWoodcuttingLevel = skills.getStatic(Skill.WOODCUTTING);
            int currentFiremakingLevel = skills.getStatic(Skill.FIREMAKING);
            int woodcuttingXP = skills.getExperience(Skill.WOODCUTTING) - startingWoodcuttingXP;
            int firemakingXP = skills.getExperience(Skill.FIREMAKING) - startingFiremakingXP;
            int xpPerHourWoodcutting = (int) (woodcuttingXP * 3600000D / runTime);
            int xpPerHourFiremaking = (int) (firemakingXP * 3600000D / runTime);

            g.setColor(Color.WHITE);
            g.drawString("Runtime: " + formatTime(runTime), 10, 30);
            g.drawString("Woodcutting Level: " + currentWoodcuttingLevel + " (+" + (currentWoodcuttingLevel - startingWoodcuttingLevel) + ")", 10, 45);
            g.drawString("Firemaking Level: " + currentFiremakingLevel + " (+" + (currentFiremakingLevel - startingFiremakingLevel) + ")", 10, 60);
            g.drawString("Woodcutting XP/Hour: " + xpPerHourWoodcutting, 10, 75);
            g.drawString("Firemaking XP/Hour: " + xpPerHourFiremaking, 10, 90);
        }

        private String formatTime(long ms) {
            long totalSeconds = ms / 1000;
            long hours = totalSeconds / 3600;
            long minutes = (totalSeconds % 3600) / 60;
            long seconds = totalSeconds % 60;
            return String.format("%02d:%02d:%02d", hours, minutes, seconds);
        }
    }

 

Edited by dubai
Link to comment
Share on other sites

  • dubai changed the title to [Open Source] Dubai's OakBurner [BETA]

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