Dextrell Posted June 28 Share Posted June 28 (edited) Hello everyone this is my first script. I'd love to grab some feedback and any progress pictures you guys post would greatly help! This bot supports all trees around draynor village up to yew trees! Make sure to start the bot in lumbridge or draynor to get it running for all the other trees! If you select Magic Trees please be within the woodcutting guild! Source Code Spoiler package com.dexcutter; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; import java.text.DecimalFormat; import java.util.Comparator; import java.util.List; import java.util.concurrent.TimeUnit; import javax.imageio.ImageIO; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import org.osbot.rs07.api.map.Position; import org.osbot.rs07.api.model.Entity; import org.osbot.rs07.api.model.RS2Object; import org.osbot.rs07.api.ui.Skill; import org.osbot.rs07.api.ui.Tab; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import org.osbot.rs07.utility.ConditionalSleep; @ScriptManifest(author = "Dextrell", info = "Woodcutting Script", name = "DexCutter", version = 2, logo = "https://i.imghippo.com/files/7akYx1724390898.png") public class DexCutter extends Script { private boolean isRunning; private long timeStarted; private long timeFinished; private long timeElapsed; private int startingXp; private int endedXp; private int xpGained; private int currentXp; private int logsChopped = 0; private int currentLevel; private int startingLevel; private int levelsGained; private boolean forestry = true; @SuppressWarnings("unused") private boolean dropLogs; private DecimalFormat df = new DecimalFormat("#"); private Font font = new Font("Consolas", Font.BOLD, 15); // Gui components private JFrame frame; private String[] treeChoices = { "Magic tree", "Tree", "Oak tree", "Willow tree", "Yew tree" }; private String[] axeChoices = { "Dragon axe", "Bronze axe", "Iron axe", "Steel axe", "Black axe", "Adamant axe", "Rune axe" }; private Player player; private BufferedImage img; /** * Regular Tree: 1278 Oak Tree: 10820 */ @Override public void onStart() { log("Initializing Script...."); frame = new JFrame("DexCutter"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setBounds(50, 50, 400, 400); JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); JLabel treeLabel = new JLabel("Select a tree type"); treeLabel.setAlignmentX(Component.CENTER_ALIGNMENT); panel.setSize(400, 400); panel.add(treeLabel); JComboBox<String> treeComboBox = new JComboBox<String>(treeChoices); treeComboBox.setMaximumSize(treeComboBox.getPreferredSize()); treeComboBox.setAlignmentX(Component.CENTER_ALIGNMENT); treeComboBox.setSelectedItem(treeChoices[0]); player = new Player(this); player.setTree(Tree.MAGIC); player.setTreeArea(player.getTree().getAreas()[0]); treeComboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub String treeSelected = treeComboBox.getSelectedItem().toString(); switch (treeSelected) { case "Tree": player.setTree(Tree.TREE); break; case "Oak tree": player.setTree(Tree.OAK); break; case "Willow tree": player.setTree(Tree.WILLOW); break; case "Yew tree": player.setTree(Tree.YEW); break; case "Magic tree": player.setTree(Tree.MAGIC); log("Setting Magic Tree"); default: player.setTree(Tree.TREE); break; } player.setTreeArea(player.getTree().getAreas()[0]); } }); JComboBox<String> axeComboBox = new JComboBox<String>(axeChoices); axeComboBox.setMaximumSize(axeComboBox.getPreferredSize()); axeComboBox.setAlignmentX(Component.CENTER_ALIGNMENT); axeComboBox.setSelectedItem(axeChoices[0]); player.setAxe(axeChoices[0]); axeComboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { player.setAxe((String) axeComboBox.getSelectedItem()); } }); panel.add(treeComboBox); panel.add(axeComboBox); JLabel dropLogsLabel = new JLabel("Drop Logs?"); panel.add(dropLogsLabel); ButtonGroup dropRadioButtonGroup = new ButtonGroup(); JRadioButton yesButton = new JRadioButton(); yesButton.setText("Yes"); // yesButton.setBounds(120, 30, 120, 50); JRadioButton noButton = new JRadioButton(); noButton.setText("No"); // noButton.setBounds(250, 30, 80, 50); noButton.setSelected(true); panel.add(yesButton); panel.add(noButton); dropRadioButtonGroup.add(yesButton); dropRadioButtonGroup.add(noButton); JButton startButton = new JButton("Start"); startButton.setAlignmentX(Component.CENTER_ALIGNMENT); startButton.addActionListener(e -> { dropLogs = yesButton.isSelected(); if (player.getTree() == null && player.getTreeArea() != null) { JOptionPane.showMessageDialog(null, "Error: Tree type not selected!"); } else { isRunning = true; timeStarted = System.currentTimeMillis(); startingXp = skills.getExperience(Skill.WOODCUTTING); startingLevel = skills.getStatic(Skill.WOODCUTTING); frame.dispose(); log("Selected: " + player.getTree().getName()); } }); panel.add(startButton); frame.add(panel); log("Tree selected: " + player.getTree()); img = getImage("https://iili.io/dFKcgGR.png"); //log("image: " + backgroundImage); frame.setVisible(true); } @Override public int onLoop() throws InterruptedException { if (isRunning) { if (!getInventory().isFull() && !player.getTreeArea().contains(myPlayer())) { if (getWalking().webWalk(player.getTreeArea())) { log("Walking to trees..."); if (settings.getRunEnergy() >= 70) { settings.setRunning(true); } new ConditionalSleep(8000, 10000) { @Override public boolean condition() throws InterruptedException { return false; } }; } } else if (!getInventory().isFull()) { player.chopTree(); } else { log("Inventory full."); // Walks to the bank. player.bankInventory(); } int randVal = random(0, 1000); if (randVal == 25) { log(randVal + " open friends"); openFriends(); } if(getEquipment().isWieldingWeapon("Dragon axe") && getCombat().getSpecialPercentage() == 100) { log("Activing spec..."); getCombat().toggleSpecialAttack(true, true); } if(forestry) { //check for rising roots Entity risingRoots = getObjects().closestThatContains("Rising roots"); if(risingRoots != null) { new ConditionalSleep(2000, 3000) { @Override public boolean condition() throws InterruptedException { risingRoots.interact("Chop down"); return !myPlayer().isAnimating(); } }.sleep(); } } } return random(200, 300); } @Override public void onExit() { log("Thank you for using DexCutter!"); timeFinished = System.currentTimeMillis(); endedXp = skills.getExperience(Skill.WOODCUTTING); log("Time Finished: " + timeFinished + " Exp Gathered: " + endedXp); } @Override public void onPaint(Graphics2D g) { if (isRunning) { g.setFont(font); g.setFont(g.getFont().deriveFont(15.0f)); g.setColor(Color.CYAN); g.drawRect((int)mouse.getPosition().getX()-10, (int)mouse.getPosition().getY()-10, 20, 20); g.drawLine((int)mouse.getPosition().getX(), 0, (int)mouse.getPosition().getX(), 500); g.drawLine(0, (int)mouse.getPosition().getY(), 800, (int)mouse.getPosition().getY()); g.setColor(Color.RED); timeElapsed = System.currentTimeMillis() - this.timeStarted; if (img != null) g.drawImage(img, 0, 340, img.getWidth(), img.getHeight()-25, null); g.drawString("Time ran for:", 40, 395); g.drawString(ft(timeElapsed), 150, 395); currentXp = skills.getExperience(Skill.WOODCUTTING); xpGained = currentXp - startingXp; currentLevel = skills.getStatic(Skill.WOODCUTTING); g.drawString("Xp Gained:" + xpGained, 40, 420); levelsGained = currentLevel - startingLevel; g.drawString("Levels gained:" + levelsGained, 260, 420); logsChopped = (int) (xpGained / player.getTree().getExperience()); g.drawString("Logs chopped:" + df.format(logsChopped), 40, 445); } } private String ft(long duration) // Makes time 0:0:0 { String res = ""; long days = TimeUnit.MILLISECONDS.toDays(duration); long hours = TimeUnit.MILLISECONDS.toHours(duration) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration)); long minutes = TimeUnit.MILLISECONDS.toMinutes(duration) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration)); long seconds = TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)); if (days == 0) { res = (hours + ":" + minutes + ":" + seconds); } else { res = (days + ":" + hours + ":" + minutes + ":" + seconds); } return res; } public RS2Object getClosestObject(Script script, Position position) { List<RS2Object> regionObjects = script.objects.getAll(); if (regionObjects.size() == 0) { script.log("No objects found"); return null; } else if (regionObjects.size() == 1) { return regionObjects.get(0); } regionObjects.sort(new Comparator<RS2Object>() { @Override public int compare(RS2Object o1, RS2Object o2) { return o1.getPosition().distance(position) - o2.getPosition().distance(position); } }); return regionObjects.get(0); } public void openInventory() { getTabs().open(Tab.INVENTORY); new ConditionalSleep(450, 3000) { @Override public boolean condition() throws InterruptedException { return getTabs().getOpen().equals(Tab.INVENTORY); } }.sleep(); } public void openFriends() { getTabs().open(Tab.FRIENDS); new ConditionalSleep(450, 3000) { @Override public boolean condition() throws InterruptedException { return getTabs().getOpen().equals(Tab.FRIENDS); } }.sleep(); openInventory(); } private BufferedImage getImage(String url) // Get's the background image. { try { log("image read"); return ImageIO.read(new URL(url)); } catch (IOException e) { e.printStackTrace(); } return null; } } package com.dexcutter; import org.osbot.rs07.api.map.Area; public enum Tree { TREE("Tree", 25, 1278, 2000, 8000, new Area[]{new Area(3146, 3228, 3204, 3213)}), OAK("Oak tree", 10820, 37.5, 8000, 10000, new Area[] {new Area(3146, 3228, 3164, 3213)}), WILLOW("Willow tree", 8481, 67.5, 10000, 13000, new Area[] {new Area(3087, 3225, 3092, 3239)}), YEW("Yew tree", 10822, 175, 15000, 20000, new Area[] {new Area(3145,3251,3150,3257), new Area(3150, 3223, 3154, 3230), new Area(3164, 3218, 3168, 3222), new Area(3183, 3224, 3188, 3228)}); private String name; private int objectId; private double experience; private int minTime; private int maxTime; private Area[] areas; private Tree(String name, int objectId, double experience, int minTime, int maxTime, Area[] areas) { this.name = name; this.objectId = objectId; this.experience = experience; this.minTime = minTime; this.maxTime = maxTime; this.areas = areas; } public String getName() { return this.name; } public int getObjectId() { return this.objectId; } public double getExperience() { return this.experience; } public int getMinTime() { return minTime; } public int getMaxTime() { return maxTime; } public Area[] getAreas() { return this.areas; } } Media Spoiler Jar Download Spoiler Download Jar Edited September 9 by Dextrell Update fixing a bug with willows Quote Link to comment Share on other sites More sharing options...
yfoo Posted June 29 Share Posted June 29 (edited) 1. Put the image in resources so that a network request is not needed then use SystemIO to get thz. There is no guarantee that the hosting service won't delete your image randomly. Refer to the link below for a more concise tutorial. RS2Object treeObject = getObjects().closest(tree.getObjectId()); if (treeObject == null) { this.log("Yew tree is null...."); } log("does it contain tree obj? " + treeArea.contains(treeObject)); 2. Use the filter API. This can be simplified to something like ``` RS2Object treeObject = getObjects().closest(rs2Object -> rs2Object.getId() == tree.getObjectId() && treeArea.contains(rs2Object); ``` This will ensure tree interactions are only done on trees of a certain type (regular, oak, willow, ect.) and are in the designated area. 3. The Paint and GUI are crammed in the the Script class its hard to read. Consider splitting these up into individual classes. You can designate a painter class by having it implement Painter. Then in onStart calling getBot().addPainter(<paint instance>) Make sure to remove this in onStop with getBot().removePainter(<same instance as above>) Otherwise the paint may not get cleaned up if the script crashes/exits. 4. You don't need to call this if you are intending to immediately interact with the object. The interaction will do this if the object is not on screen. if (getCamera().toEntity(treeObject)) Its a great first attempt. Ill take a look at the gui later. Edited June 29 by yfoo 1 Quote Link to comment Share on other sites More sharing options...
yfoo Posted June 30 Share Posted June 30 As for the GUI error public void onStart() { log("Initializing Script...."); frame = new JFrame("DexCutter"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setBounds(50, 50, 400, 400); frame.setVisible(true); //<<<<<<<<<<<<<<<<< ... Move frame.setVisible(true); to the end of onStart(). It is set to visible before al the other components are added to the panel. 1 Quote Link to comment Share on other sites More sharing options...
Dextrell Posted July 1 Author Share Posted July 1 On 6/29/2024 at 5:20 PM, yfoo said: 1. Put the image in resources so that a network request is not needed then use SystemIO to get thz. There is no guarantee that the hosting service won't delete your image randomly. Refer to the link below for a more concise tutorial. RS2Object treeObject = getObjects().closest(tree.getObjectId()); if (treeObject == null) { this.log("Yew tree is null...."); } log("does it contain tree obj? " + treeArea.contains(treeObject)); 2. Use the filter API. This can be simplified to something like ``` RS2Object treeObject = getObjects().closest(rs2Object -> rs2Object.getId() == tree.getObjectId() && treeArea.contains(rs2Object); ``` This will ensure tree interactions are only done on trees of a certain type (regular, oak, willow, ect.) and are in the designated area. 3. The Paint and GUI are crammed in the the Script class its hard to read. Consider splitting these up into individual classes. You can designate a painter class by having it implement Painter. Then in onStart calling getBot().addPainter(<paint instance>) Make sure to remove this in onStop with getBot().removePainter(<same instance as above>) Otherwise the paint may not get cleaned up if the script crashes/exits. 4. You don't need to call this if you are intending to immediately interact with the object. The interaction will do this if the object is not on screen. if (getCamera().toEntity(treeObject)) Its a great first attempt. Ill take a look at the gui later. Thank you so much for the useful insight I'll make those changes! You're right about the painter thank you so much for the tips! Quote Link to comment Share on other sites More sharing options...
Dextrell Posted August 23 Author Share Posted August 23 (edited) On 6/29/2024 at 5:20 PM, yfoo said: 1. Put the image in resources so that a network request is not needed then use SystemIO to get thz. There is no guarantee that the hosting service won't delete your image randomly. Refer to the link below for a more concise tutorial. RS2Object treeObject = getObjects().closest(tree.getObjectId()); if (treeObject == null) { this.log("Yew tree is null...."); } log("does it contain tree obj? " + treeArea.contains(treeObject)); 2. Use the filter API. This can be simplified to something like ``` RS2Object treeObject = getObjects().closest(rs2Object -> rs2Object.getId() == tree.getObjectId() && treeArea.contains(rs2Object); ``` This will ensure tree interactions are only done on trees of a certain type (regular, oak, willow, ect.) and are in the designated area. 3. The Paint and GUI are crammed in the the Script class its hard to read. Consider splitting these up into individual classes. You can designate a painter class by having it implement Painter. Then in onStart calling getBot().addPainter(<paint instance>) Make sure to remove this in onStop with getBot().removePainter(<same instance as above>) Otherwise the paint may not get cleaned up if the script crashes/exits. 4. You don't need to call this if you are intending to immediately interact with the object. The interaction will do this if the object is not on screen. if (getCamera().toEntity(treeObject)) Its a great first attempt. Ill take a look at the gui later. I've tried loading the image as a resource countless of times i set a "res" folder as a resource my file structure is the following (I made sure the res folder was set as a resource folder) DexCutter -> src com.dexcutter <- code goes here -> res img.png It will always be null I've tried loading it many different ways even did DexCutter.class.getResourceAsStream The only thing I can consider doing is having a downloader that gets the image online and puts it in the data folder. try { backgroundImage = ImageIO.read(getScriptResourceAsStream("img.png")); } catch (IOException e) { log(e); } Edited August 23 by Dextrell Quote Link to comment Share on other sites More sharing options...
yfoo Posted August 24 Share Posted August 24 10 hours ago, Dextrell said: I've tried loading the image as a resource countless of times i set a "res" folder as a resource my file structure is the following (I made sure the res folder was set as a resource folder) DexCutter -> src com.dexcutter <- code goes here -> res img.png It will always be null I've tried loading it many different ways even did DexCutter.class.getResourceAsStream The only thing I can consider doing is having a downloader that gets the image online and puts it in the data folder. try { backgroundImage = ImageIO.read(getScriptResourceAsStream("img.png")); } catch (IOException e) { log(e); } Path is wrong. its in /res, and getScriptResourceAsStream("img.png") does not have /res in it. Quote Link to comment Share on other sites More sharing options...
Dextrell Posted August 24 Author Share Posted August 24 17 hours ago, yfoo said: Path is wrong. its in /res, and getScriptResourceAsStream("img.png") does not have /res in it. I've done that as well it doesn't seem to find the file but when I extracted the jar it doesnt place the images in a res folder it only contains it within the root folder of that jar Quote Link to comment Share on other sites More sharing options...
Dextrell Posted September 9 Author Share Posted September 9 Fixed a bug with willow trees, cheers! Thank you to those that reported it to me Quote Link to comment Share on other sites More sharing options...