Luxe 83 Posted July 7, 2024 I struggled to find some good and recent examples of how to add webnodes on the forums so i decided to share my code and how i went about it. If you have any improvements, feel free to post a comment. Start by enabling webnodes in the client When you do this you should be able to see webnodes in the mini map and you'll be able to see your added nodes once you start your script ---------------------------------------------------------------------------------------------------------------------------------------------- To start off there are different types of nodes you can add: I dont know the difference between an abstract and basic webnode, but i'll be using abstract webnodes for the general locations (e.g. Tiles). If you happen to know the difference, please leave a comment. I start off by mapping the Tiles for the gameobjects that are interactable to get to a location. Tile agilityStartGameObjectTile = new Tile(2843, 3693, 0); Tile caveStartGameObjectTile = new Tile(2839, 3689, 0); Tile trollLadderGameObjectTile = new Tile(2831, 10077, 2); Then i add a webnode next to them (e.g. a walkable tile next to the object) AbstractWebNode agilityStartBN = new BasicWebNode(2844,3693,0); agilityStartBN.addDualConnections(WebFinder.getWebFinder().getNearestGlobal(agilityStartBN.getTile(), 15)); Now that i added the abstract web node for the shortcut, i need to add the shortcut. AgilityWebNode trollheimAgility = new AgilityWebNode(agilityStartGameObjectTile.getX(), agilityStartGameObjectTile.getY(), agilityStartGameObjectTile.getZ()); trollheimAgility.setObjectName("Rocks"); trollheimAgility.setAction("Climb"); trollheimAgility.setLevel(73); agilityStartBN.addDualConnections(trollheimAgility); And finally i have to add it to my webfinder webFinder.addWebNodes(trollheimAgility); --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The full code to get to the herb patch includes going through the cave, using the ladder inside the cave and the agility shortcut. I start off by declaring my webfinder in my main method: public static final WebFinder webFinder = WebFinder.getWebFinder(); then i create a function for my webnodes package Webnodes; import org.dreambot.api.methods.map.Tile; import org.dreambot.api.methods.walking.pathfinding.impl.web.WebFinder; import org.dreambot.api.methods.walking.web.node.AbstractWebNode; import org.dreambot.api.methods.walking.web.node.impl.AgilityWebNode; import org.dreambot.api.methods.walking.web.node.impl.BasicWebNode; import org.dreambot.api.methods.walking.web.node.impl.EntranceWebNode; public class TrollheimPatch { public static void WebnodeAdditionTrollheimPatch(WebFinder webFinder) { Tile agilityStartGameObjectTile = new Tile(2843, 3693, 0); Tile caveStartGameObjectTile = new Tile(2839, 3689, 0); Tile trollLadderGameObjectTile = new Tile(2831, 10077, 2); AbstractWebNode agilityStartBN = new BasicWebNode(2844,3693,0); AbstractWebNode agilityEndBN = new BasicWebNode(2838,3693,0); AbstractWebNode trollLadderInsideCaveBN = new BasicWebNode(2831,10076,2); AbstractWebNode trollLadderOutsideCaveBN = new BasicWebNode(2831,3676,0); AbstractWebNode trollHeimToolLeprechaunBN = new BasicWebNode(2827,3685,0); AbstractWebNode trollHeimherbPatchBN = new BasicWebNode(2826,3693,0); AbstractWebNode caveStartBN = new BasicWebNode(2840,3690,0); AbstractWebNode insideCave = new BasicWebNode(2837,10090,2); AbstractWebNode middleCave1 = new BasicWebNode(2836,10078,2); AbstractWebNode middleCave2 = new BasicWebNode(2839,10063,2); AbstractWebNode middleCave3 = new BasicWebNode(2839,10057,2); AbstractWebNode kobCave = new BasicWebNode(2831,10063,2); agilityStartBN.addDualConnections(WebFinder.getWebFinder().getNearestGlobal(agilityStartBN.getTile(), 15)); caveStartBN.addDualConnections(WebFinder.getWebFinder().getNearestGlobal(caveStartBN.getTile(), 15)); EntranceWebNode cave = new EntranceWebNode(caveStartGameObjectTile.getX(), caveStartGameObjectTile.getY(), caveStartGameObjectTile.getZ()); cave.setEntityName("Stronghold"); // Name of entrance 1 cave.setAction("Enter"); cave.addDualConnections(insideCave); insideCave.addDualConnections(middleCave1); caveStartBN.addDualConnections(cave); // AbstractWebNode enterCaveBN = new BasicWebNode(caveStartGameObjectTile.getX(),caveStartGameObjectTile.getY(),0); middleCave1.addDualConnections(middleCave2); middleCave2.addDualConnections(middleCave3); middleCave3.addDualConnections(kobCave); kobCave.addDualConnections(trollLadderInsideCaveBN); EntranceWebNode ladder = new EntranceWebNode(trollLadderGameObjectTile.getX(), trollLadderGameObjectTile.getY(), trollLadderGameObjectTile.getZ()); ladder.setEntityName("Troll ladder"); // Name of entrance 1 ladder.setAction("Climb-up"); ladder.addDualConnections(trollLadderInsideCaveBN,trollLadderOutsideCaveBN); AgilityWebNode trollheimAgility = new AgilityWebNode(agilityStartGameObjectTile.getX(), agilityStartGameObjectTile.getY(), agilityStartGameObjectTile.getZ()); trollheimAgility.setObjectName("Rocks"); trollheimAgility.setAction("Climb"); trollheimAgility.setLevel(73); agilityStartBN.addDualConnections(trollheimAgility); trollheimAgility.addDualConnections(agilityEndBN); agilityEndBN.addDualConnections(trollHeimherbPatchBN, trollHeimToolLeprechaunBN); trollLadderOutsideCaveBN.addDualConnections(trollHeimToolLeprechaunBN); trollHeimToolLeprechaunBN.addDualConnections(trollHeimherbPatchBN); AbstractWebNode[] webNodes = { trollLadderInsideCaveBN, trollLadderOutsideCaveBN, trollHeimToolLeprechaunBN, trollHeimherbPatchBN, caveStartBN, insideCave, middleCave1, middleCave3, kobCave, agilityStartBN, agilityEndBN }; webFinder.addWebNodes(cave, ladder, trollheimAgility); webFinder.addWebNodes(trollheimAgility); webFinder.addWebNodes(webNodes); } } And finally i call the function in my OnStart in main WebnodeAdditionTrollheimPatch(webFinder); Based on requirements, this code will now take the shortest path to the destination. Agility is shortest IF the user has 73 agility. tot67 1
Luxe 83 Author Posted July 9, 2024 Updating to add a few snippets from the discord, credits to @Pyfa AbstractWebNode ropeSwing = new AbstractWebNode(2709, 3209, 0) { @Override public boolean hasRequirements() { return true; } @Override public boolean execute() { if (!Players.getLocal().getTile().equals(new Tile(this.getX(), this.getY(), this.getZ()))) { if (Walking.shouldWalk(8)) { Walking.walk(new Tile(this.getX(), this.getY(), this.getZ())); } } else if (GameObjects.closest(23568) != null) { GameObjects.closest(23568).interact("Swing-on"); } Tile endTile = new Tile(2704, 3209, 0); return Sleep.sleepUntil(() -> Players.getLocal().getTile().equals(endTile), 2000); } @Override public boolean forceNext() { return true; } }; Teleport lunchByTheLancalliums = new Teleport() { @Override public int getX() { return 1714; } @Override public int getY() { return 3610; } @Override public int getZ() { return 0; } @Override public boolean hasRequirements() { return (Equipment.contains(item -> item.getName().contains("Kharedst's memoirs")) || Equipment.contains(item -> item.getName().contains("Book of the dead"))) && PlayerSettings.getBitValue(6035) >= 1 && Quests.isFinished(PaidQuest.THE_DEPTHS_OF_DESPAIR); } @Override public boolean execute() { Tile endTile = new Tile(getX(), getY(), getZ()); return Equipment.interact(EquipmentSlot.SHIELD, "Lunch by the Lancalliums") && Sleep.sleepUntil(() -> endTile.distance() < 20, 10000); } }; WebFinder.getWebFinder().addWebNode(new TeleportWebNode(lunchByTheLancalliums)); EntranceWebNode entrance = new EntranceWebNode(startTile.getX(), startTile.getY(), startTile.getZ()); entrance.setEntityName("Trapdoor"); entrance.setAction("Open"); entrance.setActions(new String[]{"Open", "Climb-down"}); entrance.addConnections(startClosestNode); startClosestNode.addConnections(entrance); AbstractWebNode fossilIslandShip = new AbstractWebNode(startTile.getX(), startTile.getY(), startTile.getZ()) { @Override public boolean hasRequirements() { return true; } @Override public boolean execute() { GameObject rowboat = GameObjects.closest("Rowboat"); if (rowboat != null) { rowboat.interact("Travel"); sleepUntil(() -> Dialogues.areOptionsAvailable(), 10000, 10); if (Dialogues.areOptionsAvailable()) { Dialogues.chooseOption("Row out to sea."); } } Tile endTile = new Tile(3769, 3898, 0); return Sleep.sleepUntil(() -> endTile.distance() < 20, 2000); } }; Tile brimhavenTile = new Tile(2772, 3227, 0); Tile ardougneTile = new Tile(2675, 3275, 0); Tile rimmingtonTile = new Tile(2915, 3225, 0); // Brimhaven ShipWebNodes WebFinder.getWebFinder().addWebNode(new ShipWebNode(brimhavenTile, ardougneTile, "Captain Barnaby", "Ardougne", () -> Inventory.count("Coins") >= 30)); WebFinder.getWebFinder().addWebNode(new ShipWebNode(brimhavenTile, rimmingtonTile, "Captain Barnaby", "Rimmington", () -> Inventory.count("Coins") >= 30)); // Ardougne ShipWebNodes WebFinder.getWebFinder().addWebNode(new ShipWebNode(ardougneTile, brimhavenTile, "Captain Barnaby", "Brimhaven", () -> Inventory.count("Coins") >= 30)); WebFinder.getWebFinder().addWebNode(new ShipWebNode(ardougneTile, rimmingtonTile, "Captain Barnaby", "Rimmington", () -> Inventory.count("Coins") >= 30)); // Rimmington ShipWebNodes WebFinder.getWebFinder().addWebNode(new ShipWebNode(rimmingtonTile, ardougneTile, "Captain Barnaby", "Ardougne", () -> Inventory.count("Coins") >= 30)); WebFinder.getWebFinder().addWebNode(new ShipWebNode(rimmingtonTile, brimhavenTile, "Captain Barnaby", "Brimhaven", () -> Inventory.count("Coins") >= 30)); Meteorite and MaximusPrimo 2
Luxe 83 Author Posted July 9, 2024 Code for adding teleport Farming cape package Webnodes; import org.dreambot.api.methods.container.impl.Inventory; import org.dreambot.api.methods.container.impl.equipment.Equipment; import org.dreambot.api.methods.container.impl.equipment.EquipmentSlot; import org.dreambot.api.methods.map.Tile; import org.dreambot.api.methods.walking.pathfinding.impl.web.WebFinder; import org.dreambot.api.methods.walking.web.node.impl.teleports.Teleport; import org.dreambot.api.methods.walking.web.node.impl.teleports.TeleportWebNode; import org.dreambot.api.utilities.Sleep; public class FarmingCape { public static void WebnodeAdditionFarmingCapeTeleport(WebFinder webFinder) { Teleport FarmingCapeEquipmentTeleport = new Teleport() { @Override public int getX() { return 1249; } @Override public int getY() { return 3725; } @Override public int getZ() { return 0; } @Override public boolean hasRequirements() { return (Equipment.contains(item -> item.getName().contains("Farming cape") || item.getName().contains("Farming cape(t)"))); } @Override public boolean execute() { Tile endTile = new Tile(getX(), getY(), getZ()); return Equipment.interact(EquipmentSlot.CAPE, "Teleport") && Sleep.sleepUntil(() -> endTile.distance() < 20, 10000); } }; Teleport FarmingCapeInventoryTeleport = new Teleport() { @Override public int getX() { return 1249; } @Override public int getY() { return 3725; } @Override public int getZ() { return 0; } @Override public boolean hasRequirements() { return (Inventory.contains(item -> item.getName().contains("Farming cape") || item.getName().contains("Farming cape(t)"))); } @Override public boolean execute() { Tile endTile = new Tile(getX(), getY(), getZ()); return Inventory.interact(i -> i.getName().toLowerCase().contains("farming cape"), "Teleport") && Sleep.sleepUntil(() -> endTile.distance() < 20, 10000); } }; webFinder.addWebNodes(new TeleportWebNode(FarmingCapeInventoryTeleport)); webFinder.addWebNodes(new TeleportWebNode(FarmingCapeEquipmentTeleport)); } } and ofc in onstart() WebnodeAdditionFarmingCapeTeleport(webFinder);
morten1ela 31 Posted July 9, 2024 (edited) 10 hours ago, Luxe said: @Override public boolean hasRequirements() { return (Equipment.contains(item -> item.getName().contains("Farming cape") || item.getName().contains("Farming cape(t)"))); } @Override public boolean execute() { Tile endTile = new Tile(getX(), getY(), getZ()); return Equipment.interact(EquipmentSlot.CAPE, "Teleport") && Sleep.sleepUntil(() -> endTile.distance() < 20, 10000); } Instead of making two separate web nodes, consider: Edit: Changed the if statement because I realized that if you had another cape with a teleport option, it'd use that and get stuck in a teleport loop. @Override public boolean hasRequirements() { return Equipment.contains(i -> i.getName().toLowerCase().contains("farming cape")) || Inventory.contains(i -> i.getName().toLowerCase().contains("farming cape")); } @Override public boolean execute() { Tile endTile = new Tile(getX(), getY(), getZ()); if(Equipment.contains(i -> i.getName().toLowerCase().contains("farming cape"))) { return Equipment.interact(EquipmentSlot.CAPE, "Teleport") && Sleep.sleepUntil(() -> endTile.distance() < 20, 10000); } return Inventory.interact(i -> i.getName().toLowerCase().contains("farming cape"), "Teleport") && Sleep.sleepUntil(() -> endTile.distance() < 20, 10000); } Edited July 10, 2024 by morten1ela Luxe 1
Luxe 83 Author Posted September 30, 2024 Adding two-way staircase if you have a better way to do this, please share public static void addAldarinToMasteringMixologyEntranceWebNode() { AbstractWebNode stairsUpperStart = WebFinder.getWebFinder().getNearestGlobal(new Tile(1388,2918,0), 15); AbstractWebNode downstairsStart = WebFinder.getWebFinder().getNearestGlobal(new Tile(1388,9313,0), 15); EntranceWebNode StairsUpper = new EntranceWebNode(1388,2915, 0); EntranceWebNode StairsLower = new EntranceWebNode(1388,9314, 0); StairsUpper.setEntityName("Staircase"); StairsUpper.setAction("Climb-down"); stairsUpperStart.addDualConnections(StairsUpper); StairsUpper.addDualConnections(downstairsStart); StairsLower.setEntityName("Staircase"); StairsLower.setAction("Climb-up"); downstairsStart.addDualConnections(StairsLower); StairsLower.addDualConnections(stairsUpperStart); AbstractWebNode[] webNodes = {stairsUpperStart,downstairsStart}; WebFinder.getWebFinder().addWebNodes(webNodes); WebFinder.getWebFinder().addWebNodes(StairsUpper,StairsLower); } jesssterrr 1
HTM 31 Posted October 1, 2024 I've never really messed with webnodes and appreciate the examples. I still dont fully comprehend the exact need for webnodes either. Is it not just as easy to create an endpoint box, get a randomized tile within it and use the dreambot built in Abstract Walking to arrive at the point? It could even be a specified tile within a radius of the origin tile.Im just curious if i should switch to using webnode if Abstract suits my current needs.
Luxe 83 Author Posted October 1, 2024 9 minutes ago, HTM said: I've never really messed with webnodes and appreciate the examples. I still dont fully comprehend the exact need for webnodes either. Is it not just as easy to create an endpoint box, get a randomized tile within it and use the dreambot built in Abstract Walking to arrive at the point? It could even be a specified tile within a radius of the origin tile.Im just curious if i should switch to using webnode if Abstract suits my current needs. from my understanding webnodes are a way to map paths and walkable areas with a minimal computing resources. The DB team maps most places, but recent additions to the game or rarely explored areas are not as commonly mapped. It could even be a specified tile within a radius of the origin - This doesn't guarantee that the tile is walkable, there could be gameobjects on that tile or there could be walls or doors hindering you from arriving at that tile. maybe @Pandemic can cover what I cant? HTM 1
morten1ela 31 Posted October 1, 2024 (edited) 6 hours ago, HTM said: I've never really messed with webnodes and appreciate the examples. I still dont fully comprehend the exact need for webnodes either. Is it not just as easy to create an endpoint box, get a randomized tile within it and use the dreambot built in Abstract Walking to arrive at the point? It could even be a specified tile within a radius of the origin tile.Im just curious if i should switch to using webnode if Abstract suits my current needs. Webnodes are what the path finder uses to path to a certain location when you use Walking.walk from a distant location. Let's say you're in Lumbridge and want to walk to Entrana. The web path finder will create a path that the bot can walk along that'd use a series of basic web nodes and charter web nodes. The bot will initially path you to the boat via a bunch of basic web nodes until it reaches the boat. The CharterWebNode will have the functionality to handle talking to the monk, or, selecting the "Travel" action within its "execute" method. It can also handle any sleeps necessary to wait until it's done traveling before it starts trying to walk again. This is what makes these specialized webnodes very powerful. Without CharterWebNode's, you would have to hard code a sequence of events to walk to the destination. First, you'd have the bot walk to the monks by specifying a tile or area, then have some code where it'd talk to or select travel, then walk across the plank (the local path finder does this), finally you'd have to walk to the final destination in entrana. 6 hours ago, HTM said: Im just curious if i should switch to using webnode if Abstract suits my current needs. You should use custom web nodes when you're trying to walk to areas that are not mapped within the global list of web nodes, or if a web node doesn't have the functionality you desire. For example, when making a barrows script, you need to dig on the mounds to go inside the crypts. There are no global web nodes that handle this, and to prevent hard coding a sequence of events, I needed to make an EntranceWebNode to handle the walking on the mound and digging for each mound. This involved making a CryptEntranceNode (extends EntranceWebNode with custom functionality in the execute method) on the mound, an EntranceWebNode for the crypt stairs, and a BasicWebNode in the center of the crypt. Then, all I need to do is call Walking.walk(centerCryptTile) and the nodes+pathfinder will take care of everything. Additionally, there were some global nodes inside the maze but they didn't have the functionality that I wanted. I wanted to call Walking.walk(mazeCenterTile) and let the walker do all the work. However, due to how the global web nodes were set up, the walker relied heavily on the LocalPathFinder to deal with the doors and it led to unwanted behavior. What I did was make a MazeDoorNode that extends BasicWebNode and set its isValid method to return true if the doors have an "open" action. That way, the web nodes within the crypt will create an inherent path to the center of the maze and all I needed to to was call Walking.walk(mazeCenterTile). The local path finder handles the doors while the web finder handles the pathing to the center. Edit: Another recent web node I needed to create was a teleport web node for the crafting guild since there are none in the global web node. I created it almost exactly the same way Luxe did with his farming cape example. All I need to do is call Bank.open(BankLocation.CRAFTING_GUILD) and it will use the crafting cape to teleport while Bank.open walks to the bank. Edited October 1, 2024 by morten1ela HTM and Luxe 1 1
HTM 31 Posted October 2, 2024 Ahhh gotcha, i appreciate both responses. Especially the depths of them. It'd make sense for those scenarios for sure, most of my bot programing has been geared towards building mains so ive had very little pathing that requires those scenarios. The only thing is it may have been helpful with construction and the minigame pathings but i managed to bypass with a bulkier abstract version. Definitely some pointers to take note and practice. Appreciate it guys.
jesssterrr 7 Posted October 22, 2024 Corsair Cove: In regards to the ableToTravel boolean, I haven't actually tested to see at what stage of the quest you gain access to the "Travel" option. Because of this, that bit value of 10 might be incorrect. You could just remove that part and leave it simply as FreeQuest.CORSAIR_CURSE.isFinished();. public class CorsairCoveNode { static Tile rimmingtonShiptTile = new Tile(2910, 3226, 0); static Tile rimmingtonShipTileExit = new Tile(2578, 2837, 1); static Tile corsairShipTile = new Tile(2574, 2835, 1); static Tile corsairShipTileExit = new Tile(2909, 3230, 1); static ShipWebNode corsairShipNode = new ShipWebNode(corsairShipTile, corsairShipTileExit, "Captain Tock", "Travel", CorsairCoveNode::ableToTravel); static ShipWebNode rimmingtonShipNode = new ShipWebNode(rimmingtonShiptTile, rimmingtonShipTileExit, "Captain Tock", "Travel", CorsairCoveNode::ableToTravel); static EntranceWebNode rimmingtonPlankBoat = new EntranceWebNode(new Tile(2909, 3228, 1), "Gangplank", "Cross"); static EntranceWebNode corsairPlankBoat = new EntranceWebNode(new Tile(2578, 2838, 1), "Gangplank", "Cross"); static EntranceWebNode corsairPlankDock = new EntranceWebNode(new Tile(2578, 2839, 0), "Gangplank", "Cross"); static BasicWebNode rimmingtonPlankDock = new BasicWebNode(2909, 3227, 0); private static boolean ableToTravel() { int varbit = FreeQuest.CORSAIR_CURSE.getVarBitID(); return PlayerSettings.getBitValue(varbit) >= 10 || FreeQuest.CORSAIR_CURSE.isFinished(); } public static void addNode(WebFinder webFinder) { //Leaving island corsairPlankDock.addDualConnections(WebFinder.getWebFinder().getNearestGlobal(corsairPlankDock.getTile(), 15)); corsairPlankDock.addOutgoingConnections(corsairShipNode); corsairShipNode.addOutgoingConnections(rimmingtonPlankBoat); rimmingtonPlankBoat.addOutgoingConnections(rimmingtonPlankDock); rimmingtonPlankDock.addOutgoingConnections(WebFinder.getWebFinder().getNearestGlobal(rimmingtonPlankDock.getTile(), 15)); //Entering island rimmingtonShipNode.addIncomingConnections(WebFinder.getWebFinder().getNearestGlobal(rimmingtonShiptTile, 15)); rimmingtonShipNode.addOutgoingConnections(corsairPlankBoat); corsairPlankBoat.addOutgoingConnections(corsairPlankDock); webFinder.addWebNodes(corsairShipNode, rimmingtonShipNode, rimmingtonPlankBoat, rimmingtonPlankDock, corsairPlankBoat, corsairPlankDock); } } Luxe 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now