Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
Buy OSRS Gold

Sell OSRS Gold
NeuroGenix

[SNIPPET] WorldHopper

Recommended Posts

Posted (edited)

Updated 19/5/2020: No longer needs updating when the number of worlds changes, only needs updating if the PVP worlds change.

Using WorldHopper.get().switchToRandom(boolean allowPvp) you will hop to a random 'accessible' world. Accessible automatically filters the worlds based on whether the account has members or the skills required and will automatically remove Deadman and other worlds too.

The only thing I can think to add now is a list of previously visitied worlds, and also a hop sequence so instead of hopping randomly it hops efficiently through worlds 1-5, 6-10 etc. This would be useful for farms that use multiple accounts at the same resource and don't want to keep bumping into eachother, you could have it change sequence given too much competition in the current set of worlds.

WorldHopper Class

Spoiler
package scripts.api.login;

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

import org.tribot.api.General;
import org.tribot.api.Timing;
import org.tribot.api2007.GameTab.TABS;
import org.tribot.api2007.GameTab;
import org.tribot.api2007.Interfaces;
import org.tribot.api2007.Login;
import org.tribot.api2007.Login.STATE;
import org.tribot.api2007.types.RSInterface;
import org.tribot.api2007.types.RSInterfaceComponent;

public class WorldHopper {
	
	private static final int PARENT = 69, COMPONENT_CHILD = 17, SWITCHER_TEXT_CHILD = 2, 
		SWITCHER_BTN_PARENT = 182, SWITCHER_BTN_CHILD = 7, HAS_MEMBERS_TEXTURE_ID = 1131;
	
	private List<RSWorld> worlds;
	
	private static WorldHopper instance = null;
	
	private WorldHopper() {
		worlds = new ArrayList<RSWorld>();
	}
	
	public static WorldHopper get() {
		if(instance == null)
			instance = new WorldHopper();
		
		return instance;
	}
	
	public boolean switchToPvp() {
		if(!isInGame() || !openWorldSwitcher()) {
			General.println("ERROR: Unable to switch worlds.");
			return false;
		}
		
		if(worlds.isEmpty() && !updateWorlds()) return false;
		
		List<RSWorld> accessibleWorlds = worlds.stream().filter(w -> w.isPvp()).collect(Collectors.toList());
		
		if(accessibleWorlds.isEmpty()) {
			General.println("ERROR: Unable to find accessible Pvp world.");
			return false;
		}
		
		int randomWorld = new Random().nextInt(accessibleWorlds.size());
		RSWorld world = accessibleWorlds.get(randomWorld);
		
		return world.hopToWorld(true) && Timing.waitCondition(() -> inWorld(world.getWorldNumber()), 15000);
	}
	
	public boolean switchToRandom(boolean allowPvp) {
		if(!isInGame() || !openWorldSwitcher()) {
			General.println("ERROR: Unable to switch worlds.");
			return false;
		}
		
		if(worlds.isEmpty() && !updateWorlds()) return false;
		
		List<RSWorld> accessibleWorlds = worlds.stream().filter(w -> w.canAccessWorld(allowPvp)).collect(Collectors.toList());
		
		if(accessibleWorlds.isEmpty()) {
			General.println("ERROR: Unable to find accessible world.");
			return false;
		}
		
		int randomWorld = new Random().nextInt(accessibleWorlds.size());
		RSWorld world = accessibleWorlds.get(randomWorld);
		
		return world.hopToWorld(allowPvp) && Timing.waitCondition(() -> inWorld(world.getWorldNumber()), 15000);
	}
	
	public boolean switchToWorld(int number, boolean allowPvpWorlds) {
		if(!isInGame() || !openWorldSwitcher()) {
			General.println("ERROR: Unable to switch worlds.");
			return false;
		}
		
		if(worlds.isEmpty() && !updateWorlds()) return false;
		
		Optional<RSWorld> getWorld = worlds.stream().filter(w -> w.getWorldNumber() == number).findAny();
		
		if(!getWorld.isPresent()) {
			General.println("ERROR: Unable to find world.");
			return false;
		}
		
		RSWorld world = getWorld.get();
		
		return world.hopToWorld(allowPvpWorlds) && Timing.waitCondition(() -> inWorld(number), 15000);
	}
	
	private boolean updateWorlds() {
		RSInterfaceComponent[] components = Interfaces.get(PARENT, COMPONENT_CHILD).getChildren();
		
		if(components.length < 1 || components.length % 6 != 0) {
			General.println("ERROR: Incorrect number of components loaded.");
			return false;
		}
		
		for (int i = 0; i < components.length; i += 6) {
			int membersIndex = i + 1;
			int worldNumberIndex = i + 2;
			int playerCountIndex = i + 4;
			int worldTypeIndex = i + 5;

			RSInterface button = components[i];
			RSInterface mem = components[membersIndex];
			RSInterface num = components[worldNumberIndex];
			RSInterface plys = components[playerCountIndex];
			RSInterface type = components[worldTypeIndex];

			if (button == null || mem == null || num == null || plys == null || type == null) {
				General.println("ERROR: A component from getWorldList() was null.");
				worlds.clear();
				return false;
			}

			int membersTexture = mem.getTextureID() > 0 ? mem.getTextureID() : -1;
			int worldNumber = num.getText().length() > 0 ? Integer.valueOf(num.getText()) : -1;
			int playerCount = plys.getText().length() > 0 ? Integer.valueOf(plys.getText()) : -1;
			String worldType = type.getText().length() > 0 ? type.getText() : "-1";

			if (membersTexture == -1 || worldNumber == -1 || playerCount == -1 || worldType.contains("-1")) {
				General.println("ERROR: A component from getWorldList() hadn't loaded properly.");
				worlds.clear();
				return false;
			}

			boolean isMembers = membersTexture == HAS_MEMBERS_TEXTURE_ID;

			RSWorld world = new RSWorld(button, isMembers, worldNumber, playerCount, worldType);
			worlds.add(world);
		}
		
		return true;
	}
	
	private boolean openWorldSwitcher() {
		if(!openGameTab(TABS.LOGOUT)) return false;
		
		if(hasLoaded()) return true;
		
		RSInterface btn = Interfaces.get(SWITCHER_BTN_PARENT, SWITCHER_BTN_CHILD);
		return btn != null && !btn.isHidden() && btn.click() && Timing.waitCondition(() -> hasLoaded(), 15000);
	}
	
	public boolean hasLoaded() {
		RSInterface worldText = Interfaces.get(PARENT, SWITCHER_TEXT_CHILD);
		return worldText != null && !worldText.isHidden() && worldText.getText().contains("Current world");
	}
	
	public boolean inWorld(int world) {
		RSInterface worldText = Interfaces.get(PARENT, SWITCHER_TEXT_CHILD);
		return worldText != null && !worldText.isHidden() && worldText.getText().contains("Current world - " + world);
	}
	
	private boolean isInGame() {
		if (!Login.getLoginState().equals(STATE.INGAME)) {
			General.println("ERROR: Must be ingame to use world switcher.");
			return false;
		}
		
		return true;
	}
	
	private boolean openGameTab(GameTab.TABS tab) {
		return tab.isOpen() ? true : tab.open() && Timing.waitCondition(() -> tab.isOpen(), General.randomLong(4000, 6000));
	}

}

 

RSWorld Class

Spoiler
package scripts.api.login;

import java.util.Arrays;
import java.util.List;

import org.tribot.api.General;
import org.tribot.api.Timing;
import org.tribot.api.input.Mouse;
import org.tribot.api2007.Game;
import org.tribot.api2007.Interfaces;
import org.tribot.api2007.types.RSInterface;

public class RSWorld {
	private final int TOP_OF_SWITCHER_Y_POSITION = 240, BOTTOM_OF_SWITCHER_Y_POSITION = 416, MAX_PLAYERS = 2000,
					TOTAL_LEVEL_STRING_INDEX = 16;
	
	private RSInterface worldButton;
	
	private boolean isMembers, isFull, isDeadman, is2200Skill, is2000Skill, is1750Skill, is1500Skill, 
					is1250Skill, is750Skill, is500Skill, isClaimLeague, isPvp;
	
	private int worldNumber, playerCount, totalLevelRequired = 0;
	
	private String worldTypeText;
	
	private List<Integer> membersPvpWorlds = Arrays.asList(325, 337, 392); //REQUIRES UPDATING AS JAGEX UPDATES
	
	public RSWorld(RSInterface worldButton, boolean isMembers, int worldNumber, int playerCount, String worldTypeText) {
		this.worldButton = worldButton;
		this.isMembers = isMembers;
		this.worldNumber = worldNumber;
		this.playerCount = playerCount;
		this.worldTypeText = worldTypeText;
		
		isPvp = worldTypeText.contains("PvP");
		
		if(isPvp) {
			if(membersPvpWorlds.contains(worldNumber))
				this.isMembers = true;
		}
		
		isDeadman = worldTypeText.contains("Deadman") || worldTypeText.contains("DMM");
		is2200Skill = worldTypeText.contains("2200 skill");
		is2000Skill = worldTypeText.contains("2000 skill");
		is1750Skill = worldTypeText.contains("1750 skill");
		is1500Skill = worldTypeText.contains("1500 skill");
		is1250Skill = worldTypeText.contains("1250 skill");
		is750Skill = worldTypeText.contains("750 skill");
		is500Skill = worldTypeText.contains("500 skill");
		isClaimLeague = worldTypeText.contains("Claim");
		isFull = playerCount == MAX_PLAYERS ? true : false;
		
		if(isSkillWorld()) {
			if(is750Skill || is500Skill) {
				totalLevelRequired = Integer.valueOf(worldTypeText.substring(0, 3));
			} else {
				totalLevelRequired = Integer.valueOf(worldTypeText.substring(0, 4));
			}
		}
	}
	
	public boolean containsPlayer() {
		return Game.getCurrentWorld() == worldNumber;
	}
	
	public boolean hopToWorld(boolean allowPvp) {
		if(containsPlayer()) return true;
	
		if(!canAccessWorld(allowPvp)) {
			General.println("ERROR: Your account can't access world " + worldNumber + ". Filter List using canAccessWorld().");
			return false;
		}
		
		if(!WorldHopper.get().hasLoaded())
			return false;
		
		RSInterface scrollArea = Interfaces.get(69, 15);
		if(scrollArea == null)
			return false;
		
		if(worldButton.getAbsolutePosition().getY() < TOP_OF_SWITCHER_Y_POSITION) {
			scrollArea.hover();
			Mouse.scroll(true, General.random(1, 5));
			General.sleep(100, 300);
			return hopToWorld(allowPvp);
		}
		
		if(worldButton.getAbsolutePosition().getY() > BOTTOM_OF_SWITCHER_Y_POSITION) {
			scrollArea.hover();
			Mouse.scroll(false, General.random(1, 5));
			General.sleep(100, 300);
			return hopToWorld(allowPvp);
		}
		
		//RSInterface dangerPvp = Interfaces.get(193, 0, 3);
		if(allowPvp) {
			for(int i = 0; i < 4 ; i++) {
				if(worldButton.click() && Timing.waitCondition(() -> Interfaces.get(193, 0, 3) != null && !Interfaces.get(193, 0, 3).isHidden(), General.randomLong(1200, 1600))) {
					if(Interfaces.get(193, 0, 3).click("Switch to it")) {
						return Timing.waitCondition(() -> WorldHopper.get().inWorld(worldNumber), General.randomLong(15000, 20000));
					}
				}
			}
			return false;
		}
		
		return worldButton.click() 
				&& Timing.waitCondition(() -> WorldHopper.get().inWorld(worldNumber), General.randomLong(15000, 20000));
	}
	
	public boolean canAccessWorld(boolean allowPvp) {
		if((isPvp && !allowPvp) || isFull || isDeadman || isClaimLeague || (isMembers && !isMembersAccount()))
			return false;
		
		if(isSkillWorld() && getTotalLevel() < totalLevelRequired)
			return false;
		
		return true;
	}
	
	public boolean isPvp() {
		return isPvp;
	}
	
	public boolean isFull() {
		return isFull;
	}
	
	public boolean isSkillWorld() {
		return is2200Skill || is2000Skill || is1750Skill || is1500Skill || is1250Skill || is750Skill || is500Skill;
	}
	
	public boolean is2200SkillWorld() {
		return is2200Skill;
	}
	
	public boolean is2000SkillWorld() {
		return is2000Skill;
	}
	
	public boolean is1750SkillWorld() {
		return is1750Skill;
	}
	
	public boolean is1500SkillWorld() {
		return is1500Skill;
	}
	
	public boolean is1250SkillWorld() {
		return is1250Skill;
	}
	
	public boolean is750SkillWorld() {
		return is750Skill;
	}
	
	public boolean is500SkillWorld() {
		return is500Skill;
	}
	
	public RSInterface getWorldButton() {
		return worldButton;
	}
	
	public boolean isMembersWorld() {
		return isMembers;
	}
	
	public boolean isDeadmanWorld() {
		return isDeadman;
	}
	
	public int getWorldNumber() {
		return worldNumber;
	}
	
	public int getPlayerCount() {
		return playerCount;
	}
	
	public String getWorldTypeText() {
		return worldTypeText;
	}
	
	private boolean isMembersAccount() {
		RSInterface membershipInterface = Interfaces.get(109,  25);
		if(membershipInterface != null && membershipInterface.getText().contains("left")) {
			return true;
		}
		return false;
	}
	
	private int getTotalLevel() {
		RSInterface totalLevelInterface = Interfaces.get(320, 27);
		int totalLevel = -1;
		if(totalLevelInterface != null) {
			totalLevel = Integer.valueOf(totalLevelInterface.getText().substring(TOTAL_LEVEL_STRING_INDEX));
		}
		return totalLevel;
	}
}

 

 

Edited by NeuroGenix
Rewritten to automatically adjust to new worlds

Share this post


Link to post
Share on other sites
6 hours ago, NeuroGenix said:

Updated: Works again, let me know if you have any issues.

I’m not having any issues with the tribot world hopping, I’ve been using it for weeks with my mining script. Could it have something to do with jdk 102?

Share this post


Link to post
Share on other sites
37 minutes ago, bbuu20 said:

I’m not having any issues with the tribot world hopping, I’ve been using it for weeks with my mining script. Could it have something to do with jdk 102?

How often does your mining script hop worlds? jdk 102? I dont know if you already have, but if you look on the issues github link you'll find the debug printout that someone else posted for an ArrayOutOfBoundsException which is the same debug I got and was getting every 30-90 minutes somewhat randomly with a script that hops worlds 4 to 6 times a minute. I think that the issue is either I didn't put the proper checks in place to ensure all 1116 components in the world switcher were loaded before attempting to switch worlds (although surely the method should handle that itself? as mine attempts to) or the Tribot WorldHopper attempts to click a component before all 1116 have properly loaded when hopping worlds quickly.

In either case, the above snippet is useful, it allows you to filter the worlds incredibly easy (for those OG botters on the skill total worlds ;)), and it allows you to call the switchToRandomWorld method which no matter what account you're on, f2p, members, high/low skills, will only hop to an accessible world (so if you're 550 total it'll allow 500skill total and not 750skill total).

Share this post


Link to post
Share on other sites
42 minutes ago, NeuroGenix said:

How often does your mining script hop worlds? jdk 102? I dont know if you already have, but if you look on the issues github link you'll find the debug printout that someone else posted for an ArrayOutOfBoundsException which is the same debug I got and was getting every 30-90 minutes somewhat randomly with a script that hops worlds 4 to 6 times a minute. I think that the issue is either I didn't put the proper checks in place to ensure all 1116 components in the world switcher were loaded before attempting to switch worlds (although surely the method should handle that itself? as mine attempts to) or the Tribot WorldHopper attempts to click a component before all 1116 have properly loaded when hopping worlds quickly.

In either case, the above snippet is useful, it allows you to filter the worlds incredibly easy (for those OG botters on the skill total worlds ;)), and it allows you to call the switchToRandomWorld method which no matter what account you're on, f2p, members, high/low skills, will only hop to an accessible world (so if you're 550 total it'll allow 500skill total and not 750skill total).

Yea, the script doesn’t hop worlds quite that often, more like once or twice a minute on average, but I’ve not had an issue with it. Cool snippet either way.

Share this post


Link to post
Share on other sites
6 hours ago, bbuu20 said:

Yea, the script doesn’t hop worlds quite that often, more like once or twice a minute on average, but I’ve not had an issue with it. Cool snippet either way.

Thanks man.

I've just updated the RSWorld class to check for isFull which I'd completely forgotten about, isWorldAccessible now checks if the world is full too.

Share this post


Link to post
Share on other sites

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.


  • Our picks

    • Over the past few months, I’ve been working diligently on a new project - TRiBot X. Everything has been written from the ground up, with all of the best practices of software engineering. Every aspect of TRiBot has been re-imagined to support three main goals: flexibility, useability, and reliability.
        • Like
      • 31 replies
    • Come give us feedback on the next version of TRiBot!
        • Thanks
        • Like
      • 74 replies
    • TRiBot is looking to improve a lot of its customer relationship management, customer on boarding process, customer experience, design elements, community engagement and pretty much everything else you can imagine when it comes to marketing.

      Our goal: To ensure that the marketing done TRULY reflects the experience and does not shine an inaccurate light on what TRiBot is lacking in.

      So I ask, what do you love about TRiBot and what do you hate about TRiBot? What does O S Bot, Rune M8, PowR Bot and Dre amBot do better? (yes I purposely didn't spell it right 😂).

      Love, 

      RileyZ
        • Like
      • 23 replies
    • Over the last three weeks, I've been working on upgrading our server infrastructure. It's finally ready and is now live!

      Why?

      Increased reliability - less server errors


      Increased availability - less downtime


      Increased security - keeping us and you secure


      Increased capacity - ability to serve you better


      Increased speed - less waiting for things to load


      Faster development - server and service updates will come faster


      What are the changes?

      Move from a single AWS EC2 instance to AWS ECS (Elastic Container Service)


      Distributed computing


      Load balancing


      Git management of server files and filesystem


      Redis caching


      How?

      AWS ECS (with 10 EC2 instances)


      AWS ElastiCache (Redis)


      AWS Load Balancing


      AWS EFS (Elastic file system)


      Please bare with us as I continue to tune the server for maximum performance. Slow loading speeds may occur temporarily. I thank everyone for their patience.

      Please post on this thread if you experience any issues other than slow loading times.
        • Like
      • 51 replies
    • This release will:

      Fix prayers and world hopper API (Thanks @JoeDezzy1 and @erickho123)


      Improve banking API (Thanks @Encoded)


      Adds methods for returning and using Java Lists, rather than arrays


      Slightly randomizes some hardcoded behaviour


      Removes sleeps from waitConditions; the efficiency saving potential is negligible in these use-cases, therefore cleaner code is preferable


      Other back-end improvements





      Note: If you are using LG, please restart both the RS client and TRiBot.
        • Sad
        • Haha
        • Thanks
        • Like
      • 90 replies
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...