Jump to content

Using threads to determine something


urmom

Recommended Posts

Hey guys, I need some help. LEt's imagine my player is fighting an npc and when an npc is doing a specific animations it triggers something:

NPC npc = npcs.closest("Goblin");
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				if(npc.getAnimation()==719) {
			//do something
		}
			}
		}).start();
		new ConditionalSleep(10000) {

			@Override
			public boolean condition() throws InterruptedException {
				// TODO Auto-generated method stub
				return myPlayer().isUnderAttack();
			}
		}.sleep();

is it even possible to do something like that with threads in osbot?

Link to comment
Share on other sites

Thanks so far for the responses. I know that the example was pretty bad, but it's at its most basic structure. Not mentioning that it would recreate the thread on every loop..  I want to write a listener to listen for the animations of an NPC and do an appropriate action when detecting specific animation, I figured it would be nice to have it in a thread, now that I do know that it's not then how do I do it? Create a seperate class for it?

P.S. I even wondered of counting the projectiles while doing something, for e.g. walking somewhere

Edited by urmom
Link to comment
Share on other sites

An NPC listener is a good idea, but you don't want to go overboard with too many threads for this.

I would suggest a single instance of a class that handles all the listening, then all you have to do is tell it what to listen to and tell it what to do when it trigger something. However, anything that involves controlling your character should be handed in the main script loop and not in a separate thread, or things will get messy.

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

I used a separate thread to poll the status of grand exchange offers and notify the script execution thread of GE updates through the usage of the observer pattern. Hope this code gives an example of what to do. 

I made 3 files, an interface with a onGEUpdate callback method, a class implementing runnable; this is the code that the separate thread runs, and a utility class that keeps track of observing classes (classes implementing my interface); this class is also in charge of starting and stopping the separate thread. When the runnable class detects a GE update, it iterates through all observing classes and calls the onGEUpdate() callback.  

This is the class that holds all observing classes and the GE querying thread. It is meant to handle adding and removing Grand exchange observers. You should have something like NPCAnimObservableHandler that keep tracks of al classes that wish to be notified when a certain animation happens. 

Note that I have a stop method, call this under onExit() of your main script class! Otherwise when your script stops your second thread will never be stopped unless you terminate the client. 

package Util.GrandExchangeUtil;

import org.osbot.rs07.script.Script;

import java.util.ArrayList;
import java.util.List;

public class GrandExchangePolling {

    private List<GrandExchangeObserver> observers; //subscribed classes to ge offer changes
    private Thread geQuery;
    GrandExchangeRunnable queryRunnable;
    private static GrandExchangePolling singleton;
    private Script script;

    public static GrandExchangePolling getInstance(Script script){
        if(singleton == null)
            singleton = new GrandExchangePolling(script);
        return singleton;
    }

    private GrandExchangePolling(Script script) {
        this.observers = new ArrayList<>();
        queryRunnable = new GrandExchangeRunnable(observers, script);
        this.script = script;
    }

    public void registerObserver(GrandExchangeObserver o){
        if(!observers.contains(o)){
            observers.add(o);
            script.log(o.getClass().getSimpleName() + " is now an observer");
        }
        if(observers.size() > 0)
            startQueryingOffers();
    }

    public void removeObserver(GrandExchangeObserver o){
        observers.remove(o);
        if(observers.isEmpty())
            queryRunnable.stop();
    }

    public void stopQueryingOffers(){
        queryRunnable.stop();
    }

    private void startQueryingOffers(){
        if(geQuery == null || !queryRunnable.isRunning()){
            script.log("starting ge thread");
            geQuery = new Thread(queryRunnable);
            geQuery.start();
        }
    }
}

 

This is my thread that iterates through the GE boxes and checks if any boxes have updated since its last iteration. 


package Util.GrandExchangeUtil;

import org.osbot.rs07.api.GrandExchange;
import org.osbot.rs07.script.Script;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class GrandExchangeRunnable implements Runnable {

    private AtomicBoolean running = new AtomicBoolean(false);
    private Script script;
    private HashMap<GrandExchange.Box, Integer> amountTradedMap;
    private List<GrandExchangeObserver> observers;

    public GrandExchangeRunnable(List<GrandExchangeObserver> observers, Script script){
        this.observers = observers;
        this.script = script;
        amountTradedMap = new HashMap<>();
    }

    @Override
    public void run() {
        script.log("starting ge query thread");
        running.set(true);
        GrandExchange ge = script.getGrandExchange();
        for (GrandExchange.Box box : GrandExchange.Box.values()) {
            if(ge.getStatus(box) == GrandExchange.Status.EMPTY){
                amountTradedMap.put(box, -1);
            } else {
                int amtTraded = ge.getAmountTraded(box);
                amountTradedMap.put(box, amtTraded);
            }
        }
        while(running.get()){
            for (GrandExchange.Box box : GrandExchange.Box.values()) {
                if(ge.getStatus(box) != GrandExchange.Status.EMPTY){
                    int prevAmtTraded = amountTradedMap.get(box);
                    int amtTraded = ge.getAmountTraded(box);
                    if(prevAmtTraded != -1){
                        if(amtTraded != prevAmtTraded
                                || ge.getStatus(box) == GrandExchange.Status.FINISHED_BUY
                                || ge.getStatus(box) == GrandExchange.Status.FINISHED_SALE){
                            for(Iterator<GrandExchangeObserver> iter = observers.iterator(); iter.hasNext();){
                                GrandExchangeObserver obs = iter.next();
                                obs.onGEUpdate(box);
                                /*if(ge.getStatus(box) == GrandExchange.Status.FINISHED_BUY || ge.getStatus(box) == GrandExchange.Status.FINISHED_SALE)
                                    iter.remove();*/
                            }
                        }
                    }
                    amountTradedMap.put(box, amtTraded);
                } else
                    amountTradedMap.put(box, -1);
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        script.log("stopping ge query thread");
    }

    public void stop(){
        running.set(false);
    }

    public boolean isRunning(){
        return running.get();
    }

}

Note how my GEPolling class calls stop(). This sets a run boolean to false to allow graceful termination of this thread (it exits the while(run) loop).

Finally this is the interface defining a method that observing classes must implement. 

package Util.GrandExchangeUtil;

import org.osbot.rs07.api.GrandExchange;

public interface GrandExchangeObserver {
    void onGEUpdate(GrandExchange.Box box);
}

I actually coded this and then later realized I don't need to use a GE listener to do what I want, so I currently don't have an example usage. If you need one msg me!

Good luck with your project. 

  • Like 1
  • Heart 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...