dubai Posted August 25, 2024 Posted August 25, 2024 (edited) 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. 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 October 5, 2024 by dubai
Fanny Posted August 25, 2024 Posted August 25, 2024 Wow, you're on fire with these releases... Literally with this one! Had a quick glance over it, looks good! 1
dubai Posted August 25, 2024 Author Posted August 25, 2024 (edited) 43 minutes ago, Fanny said: Wow, you're on fire with these releases... Literally with this one! Had a quick glance over it, looks good! Very punny response, thank you These 2 open source projects were some of my early projects, still fun and they do work nicely. Edited August 25, 2024 by dubai
dubai Posted March 22 Author Posted March 22 7 hours ago, Zekay said: Link is broken cant download Re uploaded on MediaFire: https://www.mediafire.com/file/st6yqw9dy1p42o1/OakBurner.jar/file
Zekay Posted March 22 Posted March 22 15 hours ago, dubai said: Re uploaded on MediaFire: https://www.mediafire.com/file/st6yqw9dy1p42o1/OakBurner.jar/file ty