Jump to content

A Beginners Guide to Writing OSBot Scripts (where to get started!) by Apaec


Apaec

Recommended Posts

17 minutes ago, Apaec said:

Well, the reason that you're having problems is not because of syntax, it's because you're trying to put a String array inside a String array. Naturally, this isn't going to work since typing in arrays must be consistent and String[] is not the same as String.

If you've got dynamic sizing, it is much cleaner and easier to work with lists. You might want to look into those instead :)

Lists can easily be converted to and from arrays, and provide a versatile means to dynamically add and remove elements.

Good luck!

Apa

 

Ahh so it was to do with something in an entirely different aspect of Java, perfect, I'll look into those, cheers!

  • Like 1
Link to comment
Share on other sites

Seems everyone is posting their code here for some help so i may  as well do the same

 

So it seems i'm getting "Error:(36, 15) java: 'else' without 'if' " but i'm unsure as to how my else if statement is incorrect

@Override
public int onLoop() throws InterruptedException {
    Area Field = new Area(3140,3508,3154,3272);
    Entity Potato = objects.closest("Potato");
    if (!getInventory().isFull());{ //If inventory is full If statement
        if (!Field.contains(myPlayer()));{
            getWalking().webWalk(Field);
        } else {
            if(Potato !=null);
            Potato.interact("Pick");
            new ConditionalSleep(1500,500) {
                @Override
                public boolean condition() throws InterruptedException {
                    return myPlayer().isAnimating() && myPlayer().isMoving();
                }
            }.sleep();

 

All fixed! was a simple semi colon that cooked it hahah

Edited by Neku
Link to comment
Share on other sites

48 minutes ago, Malcolm_OS said:

you don't use ; while wring an if statement. so when you do this


if (!getInventory().isFull());{

it messes it up.

you should just be writing it like this 


if (!getInventory().isFull()) {

 

Figured it out haha, thanks for the response though!
now to just implement walking to the draynor bank 

Link to comment
Share on other sites

Guess who's back? Got a quick one this time :)

getKeyboard().pressKey(KeyEvent.VK_SHIFT);
		for (int i = 0; i < invSlotIndex.length; i++) {
			Item item = getInventory().getItemInSlot(i);
			if (item != null && !item.nameContains(levelFishType.getTool())) { //Look in this line
				//Interact etc
			}
		}

So I've been working on my second script still, and it's nowhere near 'testing ready', which makes knowing if certain methods from the API actually do what I THINK they do.  It's more difficult to get the answer if no one has covered the method in the forums. 

So I guess the question is, have you ever used item.nameContains() before? Does it simply grab the names of items like a sort of filter? I'm trying to drop items in a randomised fashion by grabbing the index of inventory slots, then proceeding to drop the item in that slot IF it's not something important like my Lobster pot. This is stated in my String[] named levelFishType.getTool().

I've already tried:

item.getName().equals(levelFishType.getTool())

But it's giving me this error: Unlikely argument type for equals(): String[] seems to be unrelated to String

Which is rather strange, unless .equals only strictly take strings and not string arrays.

Thanks!

Link to comment
Share on other sites

Yes, it is for shift dropping.

That aside, that was a lot of information. Very much appreciated! 

Constantly checking your bot is a skill lol. I think the way I've structured mine, it'll just break before it gets to the part I'm unsure of, probably, then forcing me to patch up my script in other areas when I'd prefer to finish up what I'm currently working on. I tend to 'finish' the script before running tests, ultimately taking the brunt of all my mistakes at once? Should definitely get into the habit of being able to test as I go for sure though.

Thanks for the help!

Link to comment
Share on other sites

11 hours ago, Glaciation96 said:

 


item.getName().equals(levelFishType.getTool())

But it's giving me this error: Unlikely argument type for equals(): String[] seems to be unrelated to String

Which is rather strange, unless .equals only strictly take strings and not string arrays.

Thanks!

Looks like Malcolm covered your question well, but I just wanted to chip in here:

The .equals method is interesting. It might seem relatively basic, but actually what is going on here is a whole lot of Object-oriented goodness which you will naturally discover more about on your scripting journey :)

Considering inheritance, at the highest level of the hierarchy is the Object class. This implements the .equals() method (behaving the same as == I believe). All classes which inherit from the Object class will (naturally) inherit this method, and most will implement a meaningful definition of the method. For example, the String class implements a version of .equals which compares character for character.

In this case, since item.getName() returns an object of type String, calling the '.equals' method refers to the String classes equals method. As a result, the method is expecting a string and will only work with such a value. It won't know what to do with a string array.

Hopefully that clears things up - it might seem confusing at first, but give it time!

Apa

  • Heart 1
Link to comment
Share on other sites

27 minutes ago, Malcolm_OS said:

I've never tried this in one of my scripts. Generally I would just use an == function but are you suggesting this wouldn't work? 

I'm also curious now.

Using == simply compares object references, and is not a value comparison. To compare values, you need something more sophisticated - this is what the equals method provides. There are also further ways to express natural orderings of your own objects such as Comparators and Comparables.

I'm not sure exactly what context you're using these methods in, but what is appropriate really depends on what you want to achieve :)

Apa

  • Like 1
Link to comment
Share on other sites

So the object class is the super class of all super classes, basically? I never looked into it before, but always assumed that a super class never inherited anything themselves. Guess there are many layers upon layers of this class hierarchy. Your explanation deepened my perspective on java, very informative, thanks!

Unfortunately, it's now question time... (sorry lol)

I'm sure you've all experienced this before, but when it comes to fishing (and possibly other activities), if you double-click the fishing spot, the player will stop fishing after looping through the fishing animation 3 times (about 5 seconds of fishing), forcing you (or the bot) to click the spot again. If you click it once, it's fine. The character will fish until the spot goes or inv is full. 

The bot will always double click if you use the standard/basic method, which is obviously 'interact -> conditional sleep'. The bot will always try to interact with the fishing spot a second time as the conditional sleep returns !myPlayer().isAnimating(). But obviously, the character doesn't fish, or initiate the fishing animation as soon as the interaction is made which is the reason. 

Is adding the general sleep(random(small sleep here)) just before the conditional sleep to return !myPlayer().isAnimating() the only way to bypass the double interaction? The drawback of this for me is that the general sleep time just slows down the onLoop rate for the bot itself. It hurts my script since I rely on the continuous looping to check if there are any free fish on the ground whilst fishing lol. Just wondering if there is a convenient method for improvement on this little drawback, maybe like the conditional sleep returning some secret condition I don't know about :) If the solution is something like implementing lambdas, just tell me there's no solution lol

Yes apa, I took your advice to make use of the continuous onLoop for my second script

Thanks fellas!

  • Like 1
Link to comment
Share on other sites

9 minutes ago, Malcolm_OS said:

I had this issue when working on my cannonball script. I ended up implementing this


                            if (myPlayer().isAnimating()) {
                                lastAnimation = System.currentTimeMillis();
                            } else if (System.currentTimeMillis() > (lastAnimation + 3000)) { 

It's a timer that will only allow the bot to interact with the entity 3 seconds after not animating. This should fix your issue with double clicking on the fishing spot when you stop animating for that little bit.

 

TBH I haven't looked into that class very much so I can't give you a solid answer on that one

I will try this, thanks a bunch!

Link to comment
Share on other sites

20 hours ago, Glaciation96 said:

So the object class is the super class of all super classes, basically? I never looked into it before, but always assumed that a super class never inherited anything themselves. Guess there are many layers upon layers of this class hierarchy. Your explanation deepened my perspective on java, very informative, thanks!

Unfortunately, it's now question time... (sorry lol)

I'm sure you've all experienced this before, but when it comes to fishing (and possibly other activities), if you double-click the fishing spot, the player will stop fishing after looping through the fishing animation 3 times (about 5 seconds of fishing), forcing you (or the bot) to click the spot again. If you click it once, it's fine. The character will fish until the spot goes or inv is full. 

The bot will always double click if you use the standard/basic method, which is obviously 'interact -> conditional sleep'. The bot will always try to interact with the fishing spot a second time as the conditional sleep returns !myPlayer().isAnimating(). But obviously, the character doesn't fish, or initiate the fishing animation as soon as the interaction is made which is the reason. 

Is adding the general sleep(random(small sleep here)) just before the conditional sleep to return !myPlayer().isAnimating() the only way to bypass the double interaction? The drawback of this for me is that the general sleep time just slows down the onLoop rate for the bot itself. It hurts my script since I rely on the continuous looping to check if there are any free fish on the ground whilst fishing lol. Just wondering if there is a convenient method for improvement on this little drawback, maybe like the conditional sleep returning some secret condition I don't know about :) If the solution is something like implementing lambdas, just tell me there's no solution lol

Yes apa, I took your advice to make use of the continuous onLoop for my second script

Thanks fellas!

There are a few options here and I would strongly suggest against having any static duration sleeps anywhere in your code.

Your first option is to try and find a condition other than animation to feed the conditionalSleep. You'll have to look through various debuggers to find this query value, if it exists.

The second option is, as Malcolm suggested, some kind of animation timer. You can either implement this in-place as Malcolm suggested, or you can run it in a concurrent thread which is my preferred method, although there are a few intricacies to Java's thread system (specifically correctly creating, running, querying and stopping the thread) which mean there are ways this can be implemented incorrectly which give unexpected behaviour.  This might be a little complex for someone as new to java as you, so perhaps the basic method is sufficient for now :). With that being said, there are plenty of tutorials available online so if you want a challenge you could always give this a go! The benefit to the concurrent system is it is entirely detached from the running of your main code, so you are not relying on an iteration of your onLoop not exceeding a certain time threshold.

Apa

  • Like 1
Link to comment
Share on other sites

1 hour ago, Apaec said:

There are a few options here and I would strongly suggest against having any static duration sleeps anywhere in your code.

Your first option is to try and find a condition other than animation to feed the conditionalSleep. You'll have to look through various debuggers to find this query value, if it exists.

The second option is, as Malcolm suggested, some kind of animation timer. You can either implement this in-place as Malcolm suggested, or you can run it in a concurrent thread which is my preferred method, although there are a few intricacies to Java's thread system (specifically correctly creating, running, querying and stopping the thread) which mean there are ways this can be implemented incorrectly which give unexpected behaviour.  This might be a little complex for someone as new to java as you, so perhaps the basic method is sufficient for now :). With that being said, there are plenty of tutorials available online so if you want a challenge you could always give this a go! The benefit to the concurrent system is it is entirely detached from the running of your main code, so you are not relying on an iteration of your onLoop not exceeding a certain time threshold.

Apa

Thanks for the additional info! I've not given Malcolm's method a go yet as I've just 'completed' my script, so just focused on fixing the minor errors right now before I move onto implementing improvements (like tackling the double interaction properly). I'll definitely want to take a look into what you suggested as well. I made a quick search, and I assume it's called java concurrency and/or multithreading which you're referring to.

Edited by Glaciation96
  • Like 1
Link to comment
Share on other sites

I return to this thread in shame, sorry guys. Mission failed. 

researched into multithreading and it looks like such a powerful tool! Thanks for bringing this up to me, but the struggle is real. Requesting guidance, please! I'll try to make this as easy to answer as possible by going through the logic in my code! Did I at least get close?

Spoiler

/* ===================== The first class/My calling method
 * Hopefully no errors in thread 1 as it's just calling, starting and terminating...
 * Makes troubleshooting easier if all issues are in thread 2!
*/
public int onLoop() throws InterruptedException {
		Thread fishCheck = new Thread(new fishInterpolation(2200));
		fishCheck.start();
		// I just started thread 2 at the beginning. Thread 2 is just a constant bool check, so shouldn't matter right?
		...
		// Then somewhere along my script, this is how I call the bool from thread 2...
		else if (!this.inventory.isFull() && !myPlayer().isAnimating()) {
			while (fishInterpolation.canInteract == true) {
				NPC fishingSpot = fishingSpot(levelFishType.getFishingSpot());
				engageFishing(fishingSpot, levelFishType.getAction());
			}
		}
		... 
		// Somewhere else in the script
		case fish:
			beginFishing();
			new ConditionalSleep(1200, (int) (Math.random() * 500 + 250)) {
				@Override
				public boolean condition() throws InterruptedException {
					return !myPlayer().isAnimating();
				}
			}.sleep();
			fishCheck.interrupt();  
			/*
			 * I stop thread 2 here, just for the onLoop to start it again...
			 * After the fishing conditional sleep.
			 */	
			break;


// ===================== The second class/Thread to call
class fishInterpolation extends Script implements Runnable {

	int delayTimer;
	long lastAnimTimeFish;
	long currentlyIdledB4Fish;
	volatile static boolean canInteract = false;

  	// Constructor: delayTimer is the time we allow the bot to interact fishing spot after being idle for so long
	public fishInterpolation(int delayTimer) { 
		this.delayTimer = delayTimer;
	}

	/*
	 * My understanding of how this bool works:
	 * Is always false, until the currentTimeMillis() of 'lastAnimTimeFish + i (which is the delayTimer in construct)
	 * has overtaken the currentTimeMillis() of 'currentlyIdledB4Fish'
	 */
	boolean toInteract(int i) {
		return currentlyIdledB4Fish > (lastAnimTimeFish + i);
	}

	@Override
	public int onLoop() throws InterruptedException { 
	// This is to keep looping the game states, constantly updating the variables to compliment the bool
		if (myPlayer().isAnimating()) {
			lastAnimTimeFish = System.currentTimeMillis();
		} else if (!myPlayer().isAnimating()) {
			currentlyIdledB4Fish = System.currentTimeMillis();
		}
		return random(100, 300);
	}

	public void run() {
		for (int i = 0; i < 1; i = 0) { // Infinite looping until interrupted, just so the thread (when started) keeps updating the bool?
			while (toInteract(delayTimer) == false) {
				canInteract = false;
			}
			canInteract = true;
		}
	}
}

 

 
 
 
 
 
 

For context, what I shared are the only changes that I made, in regards to trying to implement multithreading... Also, the bot worked before this, albeit the multiple interactions to fish.

When I start the bot, I can't tell what's wrong really... The bot doesn't even do anything and then the client goes incredibly slow, then crashes. I'm guessing it's due to my infinite loop? But isn't that just to keep checking/updating the 1 bool? 

Since I wrote the code, my snippet looks quite easy to read for me, but obviously, it'll be different for other people. I hope I've made answering this as easy as possible! There could be a couple things wrong, or a million. If it's just a messy pile of mistakes making it too much effort to answer, just let me know. That way at least I know I'm not even close, so instead of making minor changes to try getting this to work, I can just scrap it for a whole new approach to the multithreading issue.

Thanks a bunch fellas. 

EDIT: Improving readability

Edited by Glaciation96
Link to comment
Share on other sites

15 hours ago, Glaciation96 said:

I return to this thread in shame, sorry guys. Mission failed. 

researched into multithreading and it looks like such a powerful tool! Thanks for bringing this up to me, but the struggle is real. Requesting guidance, please! I'll try to make this as easy to answer as possible by going through the logic in my code! Did I at least get close?

  Hide contents


/* ===================== The first class/My calling method
 * Hopefully no errors in thread 1 as it's just calling, starting and terminating...
 * Makes troubleshooting easier if all issues are in thread 2!
*/
public int onLoop() throws InterruptedException {
		Thread fishCheck = new Thread(new fishInterpolation(2200));
		fishCheck.start();
		// I just started thread 2 at the beginning. Thread 2 is just a constant bool check, so shouldn't matter right?
		...
		// Then somewhere along my script, this is how I call the bool from thread 2...
		else if (!this.inventory.isFull() && !myPlayer().isAnimating()) {
			while (fishInterpolation.canInteract == true) {
				NPC fishingSpot = fishingSpot(levelFishType.getFishingSpot());
				engageFishing(fishingSpot, levelFishType.getAction());
			}
		}
		... 
		// Somewhere else in the script
		case fish:
			beginFishing();
			new ConditionalSleep(1200, (int) (Math.random() * 500 + 250)) {
				@Override
				public boolean condition() throws InterruptedException {
					return !myPlayer().isAnimating();
				}
			}.sleep();
			fishCheck.interrupt();  
			/*
			 * I stop thread 2 here, just for the onLoop to start it again...
			 * After the fishing conditional sleep.
			 */	
			break;


// ===================== The second class/Thread to call
class fishInterpolation extends Script implements Runnable {

	int delayTimer;
	long lastAnimTimeFish;
	long currentlyIdledB4Fish;
	volatile static boolean canInteract = false;

  	// Constructor: delayTimer is the time we allow the bot to interact fishing spot after being idle for so long
	public fishInterpolation(int delayTimer) { 
		this.delayTimer = delayTimer;
	}

	/*
	 * My understanding of how this bool works:
	 * Is always false, until the currentTimeMillis() of 'lastAnimTimeFish + i (which is the delayTimer in construct)
	 * has overtaken the currentTimeMillis() of 'currentlyIdledB4Fish'
	 */
	boolean toInteract(int i) {
		return currentlyIdledB4Fish > (lastAnimTimeFish + i);
	}

	@Override
	public int onLoop() throws InterruptedException { 
	// This is to keep looping the game states, constantly updating the variables to compliment the bool
		if (myPlayer().isAnimating()) {
			lastAnimTimeFish = System.currentTimeMillis();
		} else if (!myPlayer().isAnimating()) {
			currentlyIdledB4Fish = System.currentTimeMillis();
		}
		return random(100, 300);
	}

	public void run() {
		for (int i = 0; i < 1; i = 0) { // Infinite looping until interrupted, just so the thread (when started) keeps updating the bool?
			while (toInteract(delayTimer) == false) {
				canInteract = false;
			}
			canInteract = true;
		}
	}
}

 

 
 
 
 
 
 

For context, what I shared are the only changes that I made, in regards to trying to implement multithreading... Also, the bot worked before this, albeit the multiple interactions to fish.

When I start the bot, I can't tell what's wrong really... The bot doesn't even do anything and then the client goes incredibly slow, then crashes. I'm guessing it's due to my infinite loop? But isn't that just to keep checking/updating the 1 bool

Since I wrote the code, my snippet looks quite easy to read for me, but obviously, it'll be different for other people. I hope I've made answering this as easy as possible! There could be a couple things wrong, or a million. If it's just a messy pile of mistakes making it too much effort to answer, just let me know. That way at least I know I'm not even close, so instead of making minor changes to try getting this to work, I can just scrap it for a whole new approach to the multithreading issue.

Thanks a bunch fellas. 

EDIT: Improving readability

Just had a quick glance, i'm not sure why you're extending Script in your second class? Only one class can extend Script, otherwise the script executor won't know the entry point to your code :)

Hopefully fixing this will prevent the crashing issue which you are experiencing. You should then be able to debug further issues yourself, if there are any :)

As a side note, when developing code it is important to do it in small parts. Add one bit at a time instead of writing the whole thing and only then testing it. That will make sure you don't end up in this situation in the future :)

-Apa

  • Like 1
Link to comment
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.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...