jex124 0 Share Posted January 24, 2021 Hello first of all thanks for this tutorial. I tweaked it slightly for my needs, in the end, I have in my main class the @override method from my NpcListener (equivalent to GrandExchangeListener in your eg.). This method actually returns a List<NPC>, I would then like to use this List in my main onLoop() method, how can I do that please help? I tried various things but not working. Link to comment Share on other sites More sharing options...
Neffarion 485 Author Share Posted January 24, 2021 34 minutes ago, jex124 said: Hello first of all thanks for this tutorial. I tweaked it slightly for my needs, in the end, I have in my main class the @override method from my NpcListener (equivalent to GrandExchangeListener in your eg.). This method actually returns a List<NPC>, I would then like to use this List in my main onLoop() method, how can I do that please help? I tried various things but not working. The onLoop is independent of the listener methods. If you want to use the npc list on the onloop then you need to have a global variable that holds the values you want, update it on that new listener method and use it on the onLoop Link to comment Share on other sites More sharing options...
jex124 0 Share Posted January 24, 2021 2 hours ago, Neffarion said: The onLoop is independent of the listener methods. If you want to use the npc list on the onloop then you need to have a global variable that holds the values you want, update it on that new listener method and use it on the onLoop In this case, where should the global variable be defined? The listener is an interface so you say update the variable there? Let us take your example as the reference, if your @override onItemBought method returned an Item obj, how would you have modified your example to be able to use it inside the onLoop? Thank you for your help. Link to comment Share on other sites More sharing options...
Neffarion 485 Author Share Posted January 24, 2021 1 hour ago, jex124 said: In this case, where should the global variable be defined? The listener is an interface so you say update the variable there? Let us take your example as the reference, if your @override onItemBought method returned an Item obj, how would you have modified your example to be able to use it inside the onLoop? Thank you for your help. You can just create it on the AbstractScript itself for example for simplicity Alright, well this is very simple but for example, if you are waiting for a specific item to be bought you can make something like public class Script extends AbstractScript implements GrandExchangeListener { private final int wantedItemID = 3333; private boolean itemBought = false; @Override public void onStart() { ListenerManager.getInstance().addListener(new GrandExchangeEvent(this)); } @Override public int onLoop() { if(this.itemBought){ // collect item from GE } return 2000; } @Override public void onItemBought(GrandExchangeItemWrapper item) { if(item.getID() == this.wantedItemID){ this.itemBought = true; } } @Override public void onItemSold(GrandExchangeItemWrapper item) { } } Link to comment Share on other sites More sharing options...
jex124 0 Share Posted January 24, 2021 37 minutes ago, Neffarion said: You can just create it on the AbstractScript itself for example for simplicity Alright, well this is very simple but for example, if you are waiting for a specific item to be bought you can make something like public class Script extends AbstractScript implements GrandExchangeListener { private final int wantedItemID = 3333; private boolean itemBought = false; @Override public void onStart() { ListenerManager.getInstance().addListener(new GrandExchangeEvent(this)); } @Override public int onLoop() { if(this.itemBought){ // collect item from GE } return 2000; } @Override public void onItemBought(GrandExchangeItemWrapper item) { if(item.getID() == this.wantedItemID){ this.itemBought = true; } } @Override public void onItemSold(GrandExchangeItemWrapper item) { } } Okay so in my attempts to do this, I couldn't find success. public class Script extends AbstractScript implements NpcListener { @Override public void onStart() { ListenerManager.getInstance().addListener(new NpcEvent(this)); } List<NPC> npcList; //also tried = new ArrayList<>(); also tried declaring as public/static/protected @Override public int onLoop() { if(!(this.npcList == null)) { //Also tried without instance reference "this." for (NPC n : npcList) { n.interactForceRight("Examine"); sleep(2500); } } return 2000; } @Override public void npcExamine(NpcWrapper nW) { this.npcList = nW.getNpcList(); //wrapper simply contains List<NPC> as provided by my fire() method. } } my npcList is always null, however if I implement the npc Examine logic directly in the @Override npcExamine method, it runs. 😕 Thanks for your help. Link to comment Share on other sites More sharing options...
Neffarion 485 Author Share Posted January 25, 2021 2 hours ago, jex124 said: Okay so in my attempts to do this, I couldn't find success. public class Script extends AbstractScript implements NpcListener { @Override public void onStart() { ListenerManager.getInstance().addListener(new NpcEvent(this)); } List<NPC> npcList; //also tried = new ArrayList<>(); also tried declaring as public/static/protected @Override public int onLoop() { if(!(this.npcList == null)) { //Also tried without instance reference "this." for (NPC n : npcList) { n.interactForceRight("Examine"); sleep(2500); } } return 2000; } @Override public void npcExamine(NpcWrapper nW) { this.npcList = nW.getNpcList(); //wrapper simply contains List<NPC> as provided by my fire() method. } } my npcList is always null, however if I implement the npc Examine logic directly in the @Override npcExamine method, it runs. 😕 Thanks for your help. thats most likely your event listener logic that is returning a null list, show us the code also if you want an npc listener you should probably just pass a single npc Link to comment Share on other sites More sharing options...
jex124 0 Share Posted January 25, 2021 16 hours ago, Neffarion said: thats most likely your event listener logic that is returning a null list, show us the code also if you want an npc listener you should probably just pass a single npc Yes there was a ConcurrentModification error as my NPC list was getting updated while I was iterating through it in my NpcEvent. I solved it through calling the iteration logic through a static method. Thank you for your help! I learned a lot.. many hours well spent ps. my NpcEvent public final class NpcEvent extends AbstractEvent implements EventInterface { private final NpcListener event; public NpcEvent(AbstractScript script) { super(script); this.event = (NpcListener) parentEvent; } private final String npcStringName = "Chicken"; private List<NPC> fireNpcList;// = new ArrayList<NPC>(); @Override public void run() { while (!shouldStop() && canRun()) { if (canVerify()) { //---Scans area of npc and stores tile locations------ List<Tile> startingTile = new ArrayList<>(); for (NPC n : NPCs.all(g -> g.getName().equals(npcStringName))) { startingTile.add(n.getTile()); } //----sleeps 5.5s for any changes to npc tile locations---- try { Thread.sleep(5500); } catch (InterruptedException e) { MethodProvider.logError(e.toString()); } //-----After sleep, scans area again for npc tile locations and stores them------- List<Tile> endingTile = new ArrayList<>(); for (NPC n : NPCs.all(g -> g.getName().equals(npcStringName))) { endingTile.add(n.getTile()); } fireNpcList = handleConnected(startingTile,endingTile,npcStringName); //----------fires the response------------------ if (!fireNpcList.isEmpty()) { fire(); } //-----------clears lists to start loop again //fireNpcList.clear(); } } } private static ArrayList<NPC> handleConnected(List<Tile> a, List<Tile> b, String s) { ArrayList<NPC> npc = new ArrayList<>(); //------Logic to remove any tile locations that hasn't changed i.e. npc has not moved------- List<Tile> union = new ArrayList<Tile>(a); union.addAll(b); List<Tile> intersection = new ArrayList<Tile>(a); intersection.retainAll(b); union.removeAll(intersection); // -----------------creates a list of npc that has moved location ---------- for (NPC n : NPCs.all(g -> g.getName().equals(s) && g.isOnScreen())) { if (union.contains(n.getTile())) { npc.add(n); } } return npc; } @Override public void fire() { this.event.npcFight(new NpcWrapper(fireNpcList)); } private boolean canVerify() { return Client.isLoggedIn(); } private boolean shouldStop() { return !Client.getInstance().getScriptManager().isRunning(); } } Link to comment Share on other sites More sharing options...
Neffarion 485 Author Share Posted January 25, 2021 2 hours ago, jex124 said: Yes there was a ConcurrentModification error as my NPC list was getting updated while I was iterating through it in my NpcEvent. I solved it through calling the iteration logic through a static method. Thank you for your help! I learned a lot.. many hours well spent ps. my NpcEvent public final class NpcEvent extends AbstractEvent implements EventInterface { private final NpcListener event; public NpcEvent(AbstractScript script) { super(script); this.event = (NpcListener) parentEvent; } private final String npcStringName = "Chicken"; private List<NPC> fireNpcList;// = new ArrayList<NPC>(); @Override public void run() { while (!shouldStop() && canRun()) { if (canVerify()) { //---Scans area of npc and stores tile locations------ List<Tile> startingTile = new ArrayList<>(); for (NPC n : NPCs.all(g -> g.getName().equals(npcStringName))) { startingTile.add(n.getTile()); } //----sleeps 5.5s for any changes to npc tile locations---- try { Thread.sleep(5500); } catch (InterruptedException e) { MethodProvider.logError(e.toString()); } //-----After sleep, scans area again for npc tile locations and stores them------- List<Tile> endingTile = new ArrayList<>(); for (NPC n : NPCs.all(g -> g.getName().equals(npcStringName))) { endingTile.add(n.getTile()); } fireNpcList = handleConnected(startingTile,endingTile,npcStringName); //----------fires the response------------------ if (!fireNpcList.isEmpty()) { fire(); } //-----------clears lists to start loop again //fireNpcList.clear(); } } } private static ArrayList<NPC> handleConnected(List<Tile> a, List<Tile> b, String s) { ArrayList<NPC> npc = new ArrayList<>(); //------Logic to remove any tile locations that hasn't changed i.e. npc has not moved------- List<Tile> union = new ArrayList<Tile>(a); union.addAll(b); List<Tile> intersection = new ArrayList<Tile>(a); intersection.retainAll(b); union.removeAll(intersection); // -----------------creates a list of npc that has moved location ---------- for (NPC n : NPCs.all(g -> g.getName().equals(s) && g.isOnScreen())) { if (union.contains(n.getTile())) { npc.add(n); } } return npc; } @Override public void fire() { this.event.npcFight(new NpcWrapper(fireNpcList)); } private boolean canVerify() { return Client.isLoggedIn(); } private boolean shouldStop() { return !Client.getInstance().getScriptManager().isRunning(); } } Okay so you have some things you have done wrong, firstly you don't need a wrapper for this at all, passing an NPC to the listener methods is enough Secondly, you shouldn't filter the NPC's name here, that is done within the script when your npcFight gets called afterwards (think of the listener as being independent of your script) Make sure you null check the npc's and npc list List<Tile> startingTile = new ArrayList<>(); List<NPC> npcs = NPCs.all(g -> g != null && g.getName().equals(npcStringName)); if(npcs != null){ for (NPC n : npcs) { startingTile.add(n.getTile()); } } Regardless, I'm not entirely sure what is the objective of your listener, but you can't compare npcs with tiles alone because they can move 5 seconds is a long time to check in a listener, the delay is too large, I wouldn't do more than 2 seconds at most Also you are not sleeping the thread if canVerify fails, if you log off your listener is going to spike the cpu Link to comment Share on other sites More sharing options...
jex124 0 Share Posted January 25, 2021 17 minutes ago, Neffarion said: Okay so you have some things you have done wrong, firstly you don't need a wrapper for this at all, passing an NPC to the listener methods is enough Secondly, you shouldn't filter the NPC's name here, that is done within the script when your npcFight gets called afterwards (think of the listener as being independent of your script) Make sure you null check the npc's and npc list List<Tile> startingTile = new ArrayList<>(); List<NPC> npcs = NPCs.all(g -> g != null && g.getName().equals(npcStringName)); if(npcs != null){ for (NPC n : npcs) { startingTile.add(n.getTile()); } } Regardless, I'm not entirely sure what is the objective of your listener, but you can't compare npcs with tiles alone because they can move 5 seconds is a long time to check in a listener, the delay is too large, I wouldn't do more than 2 seconds at most Also you are not sleeping the thread if canVerify fails, if you log off your listener is going to spike the cpu Okay so if I understand correctly, 1. My listener should only do one job, i.e. track npc tile location changes and fire this list to my main script, I should do logic based on this in my main script. 2. I should add the thread sleep outside of the canVerify loop? However, since I take a scan ->sleep -> scan and compare changes, I need the sleep method inbetween, or I could implement a proper wrapper (I kept an empty wrapper just for completeness) that stores the states? . 3. From experiement, I noticed the sleep time was too much, thanks for that. So the point of all of this is, sometimes when training Ranged from a safespot, an npc might become stuck behind an obstacle eventhough it is within the bow range. In that case, my character will continously run out -> attack -> fall back to safespot. This pattern looks obvious and is inefficient. My listener tracks npc tile locations and track for changes, if npc has not moved in a timeframe, he is likely to be stuck , so I ignore him. Thanks for your help. Link to comment Share on other sites More sharing options...
Neffarion 485 Author Share Posted January 25, 2021 52 minutes ago, jex124 said: Okay so if I understand correctly, 1. My listener should only do one job, i.e. track npc tile location changes and fire this list to my main script, I should do logic based on this in my main script. 2. I should add the thread sleep outside of the canVerify loop? However, since I take a scan ->sleep -> scan and compare changes, I need the sleep method inbetween, or I could implement a proper wrapper (I kept an empty wrapper just for completeness) that stores the states? . 3. From experiement, I noticed the sleep time was too much, thanks for that. So the point of all of this is, sometimes when training Ranged from a safespot, an npc might become stuck behind an obstacle eventhough it is within the bow range. In that case, my character will continously run out -> attack -> fall back to safespot. This pattern looks obvious and is inefficient. My listener tracks npc tile locations and track for changes, if npc has not moved in a timeframe, he is likely to be stuck , so I ignore him. Thanks for your help. Yes You should try to do it as I did in the example in the main post, that way you can do only scan -> compare -> sleep (the first time it runs it won't trigger anything but that isn't really relevant as it is runs often, and you are probably not needing it at that point so early) For your problem I wouldn't personally use a listener as you can just save the npc when you attack and check for movement while you wait for it to kill it Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.