Jump to content

yfoo

Lifetime Sponsor
  • Posts

    175
  • Joined

  • Last visited

  • Days Won

    1
  • Feedback

    100%

Everything posted by yfoo

  1. Buy RS3/OSRS gold, then buy bonds with that gold. About ~$2 for 14 days.
  2. It seems that hardware mouse only seems to work if the client is in focus. Is actually the case?
  3. So yesterday I started writing scripts again. The last time I wrote osbot scripts was 5 years ago. I literally just figured out why I was unable to build a new version of a script then have osbot pick it up without a restart. I somewhat remember this being a problem 5 years ago too, now no longer. All I had to do was launch the client with a DIFFERENT osbot jar than the one I set IntelliJ to compile as a dependency. Hopefully this helps someone.
  4. oops, misread an API method. Fixed.
  5. what is your inventory when you start the script.
  6. Item-Combiner Osbot script designed to automate any 2 item combination action. Source + Jar: https://github.com/PayPalMeRSGP/Item-Combiner Common use cases: stringing bows creating unf potions finishing potions doing hosidious favor by making special compost Usage Instructions Currently this script ONLY works with NPC bankers, so no bank chests. Also only works for game tasks where FOURTEEN of TWO item types of withdrawn and put together. Start script with an inventory setup with the 2 items to combine. The items are auto detected and the session's recipe will be set. Script will execute until either constituent item runs out. WARNING: I only check for the "Nothing interesting happens" String in game chat, it is the user's responsibility to ensure that they have the required level necessary! I don't know what the exact gamechat string for not having the required lvl, so if anyone can tell me I can remove this warning. Installation A precompiled jar of the source code has been provided for you under the compiled folder. Drop this under the scripts folder in your osbot user files directory located under your user folder on your computer. Special Notes This script is written to simulate a markov chain. Most actions such as item creation have been redundantly coded to be solved in multiple distinct ways. For example, When interacting with the widget to confirm to combine items, there are 3 choices of which one is randomly chosen. AFK (62.5%; 100/160): interact with the widget, move mouse offscreen, remain idle for some random time even after all items have been combined HoverBank (31.25%; 50/160): interact with widget, then right click hover the bank option, when all items have combined immedietly click to open the bank PrematureStop (6.25%; 10/160): interact with widget, right click hover the bank, before all items have combined, click to open the bank canceling combining the remaining items. This is meant to simulate a EHP player mistiming the game ticks. Percentages are calculated from relative probability weights I've set. The following line defines the above branch probabilities. Item-Combiner/src/nodes/bankingnodes/withdraw/Withdraw.java private List<Edge> bothItemsWithdrawn = Arrays.asList( new Edge(AFKCreation.class, 100), new Edge(HoverBankerCreation.class, 50), new Edge(PrematureStopCreation.class, 10)); The AFK branch probability is calcuated by taking the weight of that branch (100) divided by the total weight sum of every branch (100 + 50 + 10). So 100/160 = 0.625. If desired you can modify these probabilites to your own desires. Doing so may grant your script a different profile than every other user. Also the items slot of the two items chosen to be used on one another is random, by default item.interact(<item>) always interacts with the first item slot index matching the specified target item.
  7. Was refering to Rank 1 EHP. He got 200M agility xp within a very short period of time (1hour?) by hoarding brimhaven agility tokens then spending them all at once.
  8. Took a break from RS to play some other games. Had my fun with Black ops4, Divinity 2, MGS V, and Grim Dawn. But I miss the unique gameplay loop that writing osbot scripts + running them in OSRS has. IMO, OSRS has a reputation for being a drama filled and a somewhat toxic game. Such as... - Jmod patches in exploit for Corp beast, Then buying an audi with profits from leaking bug. - Clans DDoSing each other for $10k - Toxic clans - Youtuber chooses a controversial advertiser to earn some extra money so he can immigrate to a higher cost of living country to comfortably live with his signiticant other, but in doing so earns the ire of the toxic community. - Efficiency scape meta revolves around gaming the server's tick rate . - Agility EHP nerd messes up his ghost mouse settings and gets major macroed. Tries to cover it up on twitter. - Mobile version of game announced with large community backlash Wrong game LOL - Poor QA in 2 seperate instances resulting in max cash stacks AND non-pvp servers becoming pvp servers. - Low Quality customer support exposed when players lost items from bugs but denied any support from Jagex. Until uproar from OSRS subreddit forced some resolution. - Jed tried to reenact the Draynor Village Bank Heist but forgot to sara strike the camera. Or didn't realize that player database read operations were logged. Despite that, I love this game.
  9. Update1: @liverare helped me alot with code readability, namely... Improve the readability of CombinationRecipe.java enum by creating a seperate ItemData enum that CombinationRecipe uses. Origionally CombinationRecipe.java looked like this... public enum CombinationRecipes { AVANTOE("Avantoe", "Vial of water", "Avantoe potion (unf)", "avan", 261, 227, 103, 50, true), TOADFLAX("Toadflax", "Vial of water", "Toadflax potion (unf)", "toadfl", 2998, 227, 3002, 34, true), RANARR("Ranarr", "Vial of water", "Ranarr potion (unf)", "ranar", 257, 227, 99, 30, true), IRIT("Irit leaf", "Vial of water", "Irit potion (unf)", "irit", 259, 227, 101, 45, true), KWUARM("Kwuarm", "Vial of water", "Kwuarm potion (unf)", "kwu", 263, 227, 105, 55, true), HARRALANDER("Harralander", "Vial of water", "Harralander potion (unf)", "harra", 255, 227, 97, 21, true), ATTACK_POTION("Guam potion (unf)", "Eye of newt", "Attack potion (3)", "n/a", 91, 221, 121, 3, false), CLAY("Clay", "Jug of water", "Soft clay", "clay", 434, 1937, 1761, 1, false), AIR_BATTLESTAFF("Battlestaff", "Air orb", "Air Battlestaff", "", 1391, 573, 1397, 66, false), YEW_LONGBOW("Yew longbow (u)", "Bow string", "Yew longbow", "yew long", 66, 1777, 855, 70, false); ... variables, constructor, and getter methods } multiple fields such as the item id for vial of water (227) were repeated in every entry. This is a problem because suppouse an item id were to update; every entry would need to be changed. It is also not clear what the 4 int values in each enum were, and I wrote this. ItemData comes into play here by defining specific mappings of itemName to ItemID that my refractored CombinationRecipe uses. ItemData.java: package Util; import org.osbot.rs07.api.filter.Filter; import org.osbot.rs07.api.model.Item; //Credits to LiveRare public enum ItemData implements Filter<Item> { VIAL_OF_WATER("Vial of water", 227), CLEAN_AVANTOE("Avantoe", 261), CLEAN_TOADFLAX("Toadflax", 2998), CLEAN_IRIT("Irit leaf", 259), CLEAN_KWUARM("Kwuarm", 263), CLEAN_HARRALANDER("Harralander", 255), UNF_AVANTOE_POTION("Avantoe potion (unf)", 103), UNF_TOADFLAX_POTION("Toadflax potion (unf)", 3002), UNF_IRIT_POTION("Irit potion (unf)", 101), UNF_KWUARM_POTION("Kwuarm potion (unf)", 105), UNF_HARRALANDER_POTION("Harralander potion (unf)", 97); private String name; private int id; ItemData(String name, int id) { this.name = name; this.id = id; } @Override public String toString() { return String.format("[%s] %s", id, name); } public String getName() { return name; } public int getId() { return id; } @Override public boolean match(Item item) { return item.getId() == id || item.getName().equals(name); } } And CombinationRecipe.java now uses this enum to define recipes like so: package Util; import org.osbot.rs07.api.ui.Skill; public enum CombinationRecipes { AVANTOE_UNF_RECIPE(ItemData.CLEAN_AVANTOE, ItemData.VIAL_OF_WATER, ItemData.UNF_AVANTOE_POTION, Skill.HERBLORE, 50, true), TOADFLAX_UNF_RECIPE(ItemData.CLEAN_TOADFLAX, ItemData.VIAL_OF_WATER, ItemData.UNF_TOADFLAX_POTION, Skill.HERBLORE, 34, true), IRIT_UNF_RECIPE(ItemData.CLEAN_IRIT, ItemData.VIAL_OF_WATER, ItemData.UNF_IRIT_POTION, Skill.HERBLORE, 48, true), KWUARM_UNF_RECIPE(ItemData.CLEAN_KWUARM, ItemData.VIAL_OF_WATER, ItemData.UNF_KWUARM_POTION, Skill.HERBLORE, 55, true), HARRALANDER_UNF_RECIPE(ItemData.CLEAN_HARRALANDER, ItemData.VIAL_OF_WATER, ItemData.UNF_HARRALANDER_POTION, Skill.HERBLORE, 22, true); private ItemData primary, secondary, product; private Skill skill; private int reqLvl; private boolean canUseGE; CombinationRecipes(ItemData primary, ItemData secondary, ItemData product, Skill skill, int reqLvl, boolean canUseGE) { this.primary = primary; this.secondary = secondary; this.product = product; this.skill = skill; this.reqLvl = reqLvl this.canUseGE = canUseGE; } public ItemData getPrimary() { return primary; } public ItemData getSecondary() { return secondary; } public ItemData getProduct() { return product; } public Skill getSkill() { return skill; } public int getReqLvl() { return reqLvl; } public String getGESeachTerm() { return primary.getName().trim().split(" ")[0]; } public boolean isCanUseGE() { return canUseGE; } } The same information in the old CombinationRecipe.java is still there however now the composition of each enum value is alot more readable. Another advantage is the implementation of Filter<Item> in ItemData.java. The ItemContainer class (extended by Bank and Inventory) defines overloaded methods for contains, interact, getAmount, etc that besides taking in an item name or item ID can also take in a class defining the Filter<Item> interface. This allows me to simply write code like... inventory.contains(recipe.getPrimary()) bank.withdraw(recipe.getPrimary()), bank.withdraw(recipe.getSecondary()) and bank.deposit(recipe.getProduct()) Because each node class holds a reference to the current recipe (so all nodes know what to withdraw, interact, etc) alot of refractoring work needs to go into each class using CombinationRecipe.java. Furthermore as hinted in the MainScript.java file, every node object is passed an instance of script because for example, Withdraw nodes need API access for banking. A problem with passing script is to access api methods you need to call script.getXXX().doSomething(), or Bank bank = script.getBank() and bank.withdraw(something). Instead it is alot cleaner to have each Node extend MethodProvider and exchangeContext with a passed bot instance. That way API access code does not require a call to getXXX(). IMO I think documentation for providing API access to your classes could use some work. Especially since exchangeContext is marked as deprecated which inadvertantly encourages scriptors to pass script around. There is alot to change around and I won't commit anything until I can confirm that all refractored code runs. Anyway, thank you, that is all.
  10. Because coding and solving problems feels rewarding and fun.
  11. Its in a private github repository, so PM me github linked emails please.
  12. This script is something I worked on over my last summer vacation before starting my actual programming job. It is an item combination script aimed at goldfarming unfinished potions. For the most part it works really well. Overnight runs and so on... with special code to handle breaks. I even used it to get 99 fletching. https://imgur.com/qY9sxrx This is what the paint looks like https://imgur.com/z9F8Bhr https://imgur.com/ipOmJ6w https://imgur.com/cOCn4xG It uses my fancy crap algorithm to keep doing the same unfinished potions recipe (AVAN, TDFX, ect.) until the price margin for that recipe has fallen below a (HARD_CODED_INTEGER) OR (a previously found cached price margin of a competing recipe). Price margins are found by the insta buy and sell prices of an unfinished potion and its corresponding herb. I use a sell price of 1 and buy price of 5000 to force a buy/sell. So because of the above, if its not obvious, the script knows how to buy herbs and sell unfinished potions. The undeterministic nature of GE transactions is what I had so many issues over. For the most part my code will handle it, with minor hiccups, but it will correct itself in time. The transaction code is what I'm concerned about, basically I think its a fucking mess. A working mess but not one im happy with. If you're willing to look over my code PM me and I may give you source, i been commenting it as I was writing it so hopefully you don't get too lost. And of course, THANK YOU!' It is hosted as a private github repo so PM me your github. Im not kidding about the 40 classes thing: https://imgur.com/pGaSTJ4 Trusted please. I been around here long enough to think I know who are reasonable, or have written something I think is cool. <-WTF english @Alek @Chris @liverare @Juggles @ThatGamerBlue @Fruity @Team_Cape @Explv @Dreamo? @Im_going_by_memory_here_because_forum_is not_autocompleting_for_me. @lemons? @Team Cape @Frostbus? @apeac? If you want to look at it be warned, it can get messy. heres a primer: package ScriptClasses; import Nodes.BankingNodes.DecideRestockNode; import Nodes.BankingNodes.DepositNode; import Nodes.BankingNodes.OptionalInvFixNode; import Nodes.BankingNodes.PrimaryWithdraw.Withdraw10Primary; import Nodes.BankingNodes.PrimaryWithdraw.Withdraw14Primary; import Nodes.BankingNodes.PrimaryWithdraw.WithdrawXPrimary; import Nodes.BankingNodes.SecondaryWithdraw.Withdraw10Secondary; import Nodes.BankingNodes.SecondaryWithdraw.Withdraw14Secondary; import Nodes.BankingNodes.SecondaryWithdraw.WithdrawXSecondary; import Nodes.CreationNodes.AFKCreation; import Nodes.CreationNodes.HoverBankerCreation; import Nodes.CreationNodes.PrematureStopCreation; import Nodes.DebuggingNode; import Nodes.GENodes.*; import Nodes.MarkovChain.MarkovNodeExecutor; import Nodes.StartingNode; import Util.Margins; import Util.Statics; import org.osbot.rs07.script.MethodProvider; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import static ScriptClasses.MainScript.SCRIPT_NAME; @ScriptManifest(author = "PayPalMeRSGP", name = SCRIPT_NAME, info = "item combiner, but mainly used for unf potions", version = 0.5, logo = "") public class MainScript extends Script { static final String SCRIPT_NAME = "Item_Combinator"; private MarkovNodeExecutor executor; private DebuggingNode debug; private boolean runDebugNode = false; @Override public void onStart() throws InterruptedException { super.onStart(); Statics.script = this; markovChainSetup(); camera.movePitch(67); new ScriptPaint(this); } @Override public int onLoop() throws InterruptedException { return executor.executeThenTraverse(); } private void markovChainSetup(){ StartingNode start = new StartingNode(this); Withdraw10Primary w10P = new Withdraw10Primary(this); Withdraw14Primary w14P = new Withdraw14Primary(this); WithdrawXPrimary wXP = new WithdrawXPrimary(this); Withdraw10Secondary w10S = new Withdraw10Secondary(this); Withdraw14Secondary w14S = new Withdraw14Secondary(this); WithdrawXSecondary wXS = new WithdrawXSecondary(this); DecideRestockNode restock = new DecideRestockNode(this); DepositNode deposit = new DepositNode(this); OptionalInvFixNode fix = new OptionalInvFixNode(this); AFKCreation afk = new AFKCreation(this); HoverBankerCreation hover = new HoverBankerCreation(this); PrematureStopCreation premature = new PrematureStopCreation(this); AbortRelevantOffers abort = new AbortRelevantOffers(this); GESpinLockBuyNode buy = new GESpinLockBuyNode(this); GESpinLockSellNode sell = new GESpinLockSellNode(this); IntermittentBuy randBuy = new IntermittentBuy(this); IntermittentSell randSell = new IntermittentSell(this); InitialBuy initialBuy = new InitialBuy(this); executor = new MarkovNodeExecutor(start, w10P, w14P, wXP, w10S, w14S, wXS, restock, deposit, fix, afk, hover, premature, buy, sell, randBuy, randSell, initialBuy, abort); } @Override public void onExit() throws InterruptedException { super.onExit(); Margins.markSingletonAsNull(); ScriptPaint.geOpsEnabled = true; } } Special Notes: Margins.java - logic for GE transactions here StartNode.java - first node to be executed, and only executed once, has logic to connect to various other nodes based on state of inventory + bank. Nodes then execute in order in accordance to: https://imgur.com/CtAP0Tl ^above is out of date but gives a good enough understanding See getAdjacentNodes() for the list of successor nodes
  13. Holy shit I was literally you 9 months ago.
  14. 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.
  15. A script that records a series of interactions such as npc, widget, or item interactions then plays it back, like an ghost mouse except with defined items to click on. Is also able to serialize these interactions as some file for easy loading on script start.
  16. Snippit takes in 2 item objects or item id, randomly picks an item slot, checks if it is one of the item parameters, then uses BFS to find the corresponding item to combine with. The usage of BFS is because when it finds its goal, it is guarenteed to be the shortest path (or 1 of), therefore bfs in this case will find 2 inv slot indicies that are close to each other. Like how you would do item combination in osrs if you actually had to do it. This is an alternative to using the default; item1.interact("use") on item2.interact("use") because by default the 2 inventory items select is always the first occurance of those items. IDK if item interaction indicies are tracked by Jagex but this is a way to ofuscate any data collection on that matter. You recieve a int[2] where the 2 items are the inventory slot indicies to use on each other. There is no guarentee that int[0] is always item1 and int[1] is always item2. If you have that use case, modify my code; hint: modify the method: int[] bfsItemCombinationSlots(Item[] invItems, int item1ID, int item2ID) Because of the above stipulation, you also do not need to have code that selects the item at slot int[0] and interact with the item at slot int[1] if you wanted to randomize if you selected item 1 first or item 2 first. My code does that for you. Common Use cases: combining a herblore ingredient with a unf potion making unf potions combining a bowstring with an unstrung bow combining clay with water charged orb with battlestaff ect... Code: public int[] bfsItemCombinationSlots(Item[] invItems, Item item1, Item item2){ return bfsItemCombinationSlots(invItems, item1.getId(), item2.getId()); } private int[] bfsItemCombinationSlots(Item[] invItems, int item1ID, int item2ID){ int startIdx = ThreadLocalRandom.current().nextInt(10, 18); int otherIdx = -1; if(invItems[startIdx] != null){ //find what item occupies invItems[startIdx] and bfs with the target being the corresponding item if(invItems[startIdx].getId() == item1ID){ otherIdx = bfsTargetItemSlotHelper(invItems, item2ID, startIdx); } else if(invItems[startIdx].getId() == item2ID){ otherIdx = bfsTargetItemSlotHelper(invItems, item1ID, startIdx); } //error check if(otherIdx != -1) return new int[]{startIdx, otherIdx}; } //Some error occurred. invItems[startIdx] may be null or is an item that is not item1 or item2. Recommend doing normal inventory combine. return new int[]{-1, -1}; } private int bfsTargetItemSlotHelper(Item[] invItems, int targetItemID, int startingInvIdx){ if(startingInvIdx < 0 || startingInvIdx > 27){ throw new UnsupportedOperationException("input needs to in range [0-27]."); } Queue<Integer> bfsQ = new LinkedList<>(); boolean[] visitedSlots = new boolean[28]; bfsQ.add(startingInvIdx); visitedSlots[startingInvIdx] = true; while(!bfsQ.isEmpty()){ int current = bfsQ.poll(); if(invItems[current].getId() == targetItemID){ return current; } List<Integer> successors = getSuccessors(current); successors.forEach(slot -> { if(!visitedSlots[slot]){ visitedSlots[slot] = true; bfsQ.add(slot); } }); } return -1; } private List<Integer> getSuccessors(int invSlot) { List<Integer> successors = new ArrayList<>(); boolean canUp = false, canRight = false, canDown = false, canLeft = false; if(!(invSlot <= 3)){ //up, cannot search up if invSlot is top 4 slots successors.add(invSlot - 4); canUp = true; } if((invSlot + 1) % 4 != 0){ //right, cannot search right if invSlot is rightmost column successors.add(invSlot + 1); canRight = true; } if(!(invSlot >= 24)){ //down, cannot search down if invSlot is bottom 4 slots successors.add(invSlot + 4); canDown = true; } if(invSlot % 4 != 0){ //left, cannot search left if invSlot is leftmost column successors.add(invSlot - 1); canLeft = true; } //can search in diagonal directions if can search in its composite directions if(canUp && canRight){ successors.add(invSlot - 3); } if(canUp && canLeft){ successors.add(invSlot - 5); } if(canDown && canRight){ successors.add(invSlot + 5); } if(canDown && canLeft){ successors.add(invSlot + 3); } Collections.shuffle(successors); //randomize search order at the same search depth. return successors; } Usage: private boolean combineComponents() throws InterruptedException { Inventory inv = script.getInventory(); int[] slots = bfsItemCombinationSlots(inv.getItems(),recipe.getPrimaryItemID(), recipe.getSecondaryItemID()); //ensure algorithm did not fail. If you any other items in inventory or empty spaces, code may return {-1, -1} //if such happens, use a regular combination interaction if(slots[0] != -1 && slots[1] != -1){ if(inv.interact(slots[0], USE)){ MethodProvider.sleep(Statics.randomNormalDist(300,100)); return inv.isItemSelected() && inv.interact(slots[1], USE); } } else { if(inv.interact(USE, recipe.getPrimaryItemID())){ MethodProvider.sleep(Statics.randomNormalDist(300,100)); return inv.isItemSelected() && inv.interact(USE, recipe.getSecondaryItemID()); } } return false; }
  17. singleton.initializeModule(); well this line worked. Now im wondering how I never had this issue before, I thought I commited working code. Anyway, thanks.
  18. nope. I start script from the client. Also I start in fixed mode.
  19. Normally I can fix these myself but this is a special case. The NPE occurs under osbot's API @Alek, this issue did not occur in v2.5.8. NPE under method openGE() when calling isOpen(), an API method. Issue occurs in injection and mirror. Assistance would be appreciated. package Util.GrandExchangeUtil; import Util.Statics; import org.osbot.rs07.Bot; import org.osbot.rs07.api.Bank; import org.osbot.rs07.api.GrandExchange; import org.osbot.rs07.api.model.NPC; import org.osbot.rs07.api.ui.RS2Widget; import org.osbot.rs07.input.mouse.WidgetDestination; import org.osbot.rs07.utility.ConditionalSleep; import java.util.Arrays; import java.util.List; /** * Extended GE api to include special methods for buying/selling ingredients and finished products */ public class GrandExchangeOperations extends GrandExchange{ private static GrandExchangeOperations singleton; private GrandExchangeOperations(){} public static GrandExchangeOperations getInstance(Bot bot){ if(singleton == null){ singleton = new GrandExchangeOperations(); singleton.exchangeContext(bot); } return singleton; } /** * buys 1 copy of some item at a high price then sells it. * @param itemID the item to price check * @param searchTerm used to search the GE for the item * @return item's instant sell (margin[1]) and instant buy (margin[0]) */ public int[] priceCheckItemMargin(int itemID, String searchTerm) throws InterruptedException { sleep(2000); int[] margin = new int[2]; Box buyPredictedBox = findFreeGEBox(); String lastSuccess = ""; if(withdrawCash()){ lastSuccess = "withdrawCash"; if(openGE()){ lastSuccess = "openGE"; if(buyItem(itemID, searchTerm, random(3500, 5000), 1)){ lastSuccess = "buyItem"; if(buyPredictedBox != null){ lastSuccess = "buyPredictedBox != null"; boolean buyComplete = new ConditionalSleep(5000){ @Override public boolean condition() throws InterruptedException { return getStatus(buyPredictedBox) == Status.FINISHED_BUY && getItemId(buyPredictedBox) == itemID; } }.sleep(); if(buyComplete){ lastSuccess = "buyComplete"; margin[1] = getAmountSpent(buyPredictedBox); boolean buyCollected = new ConditionalSleep(5000){ @Override public boolean condition() throws InterruptedException { return collect(); } }.sleep(); if(buyCollected){ lastSuccess = "buyCollected"; boolean invHasItem = new ConditionalSleep(5000){ @Override public boolean condition() throws InterruptedException { return inventory.contains(itemID); } }.sleep(); Box sellPredictedBox = findFreeGEBox(); if(invHasItem && sellItem(itemID, 1, 1)){ lastSuccess = "invHasItem && sellItem"; if(sellPredictedBox != null){ lastSuccess = "sellPredictedBox != null"; boolean sellComplete = new ConditionalSleep(5000){ @Override public boolean condition() throws InterruptedException { return getStatus(sellPredictedBox) == Status.FINISHED_SALE && getItemId(sellPredictedBox) == itemID; } }.sleep(); if(sellComplete){ lastSuccess = "sellComplete"; margin[0] = getAmountSpent(sellPredictedBox); boolean sellCollected = new ConditionalSleep(5000){ @Override public boolean condition() throws InterruptedException { return collect(); } }.sleep(); if(sellCollected){ log("margin for item: " + itemID + " is " + Arrays.toString(margin)); new ConditionalSleep(3000, 500) { @Override public boolean condition() { return isOpen() && !isOfferScreenOpen(); //interface where user is prompted to buy/sell } }.sleep(); return margin; } } } } } } } } } } log("last success: " + lastSuccess); return new int[]{100000, 100000}; } /** * Sell all copies of some item in the inventory regardless of whether it is noted or unnoted * @param itemID item to buy * @param itemName item's name * @param price sell price * @return true is successful. false otherwise */ public boolean sellAll(int itemID, String itemName, int price) throws InterruptedException { if(openGE()){ sleep(1000); return sellItem(itemID, price, (int) inventory.getAmount(itemName)); } return false; } /** * buy some item with all the gp present in inventory with a max buy quantity of buyQuantityLimit. * ex1) if irits cost 1k and inventory contains 500k and buyQuantityLimit is set to 1000 * only 500 will be bought * ex2) if irits cost 1k and inventory contains 2000k and buyQuantityLimit is set to 1000 * only 1000 will be bought * @param itemID item to buy * @param searchTerm search term for ge * @param price price to buy at * @param buyQuantityLimit max quantity to buy * @return true is successful */ public boolean buyUpToLimit(int itemID, String searchTerm, int price, int buyQuantityLimit){ if(inventory.contains(995)){ if(openGE()){ int coins = (int) inventory.getAmount(995); int buyableQuantity = coins/price; int actualBuyQuantity = buyQuantityLimit > buyableQuantity ? buyableQuantity : buyQuantityLimit; return buyItem(itemID, searchTerm, price, actualBuyQuantity) && new ConditionalSleep(3000, 500) { @Override public boolean condition() { return isOpen() && !isOfferScreenOpen(); //interface where user is prompted to buy/sell } }.sleep(); } } return false; } /** * Aborts all offers for some item * @param itemName name of item to abort * @return true if successful */ public boolean abortOffersWithItem(String itemName) throws InterruptedException { if(openGE()){ boolean collected = new ConditionalSleep(5000){ @Override public boolean condition() throws InterruptedException { return collect(); } }.sleep(); Statics.longRandomNormalDelay(); List<RS2Widget> pendingOffers = getWidgets().containingText(465, itemName); if(pendingOffers != null && pendingOffers.size() > 0){ WidgetDestination offerDestination; for(RS2Widget offer: pendingOffers){ offerDestination = new WidgetDestination(bot, offer); if(mouse.click(offerDestination,true)){ boolean open = new ConditionalSleep(500) { @Override public boolean condition() throws InterruptedException { return menu.isOpen(); } }.sleep(); if(open){ if(menu.selectAction("Abort offer")){ sleep(1000); } } } } return true; } else return collected && pendingOffers == null; //if the offer is 100% complete collecting is also the same as aborting } return false; } /** * returns the offer completion percent of a buy or sell offer * @param box box to query * @return percent completion */ public double getOfferCompletionPercentage(Box box){ return ((double) getAmountTraded(box)) / getAmountToTransfer(box); } private GrandExchange.Box findFreeGEBox(){ for (GrandExchange.Box box : GrandExchange.Box.values()) { if(getStatus(box) == GrandExchange.Status.EMPTY){ return box; } } return null; //indicates no boxes are empty } private boolean openGE() { if(!isOpen()){ // Osbot API NPEs here!!! NPC grandExchangeClerk = npcs.closest("Grand Exchange Clerk"); if(grandExchangeClerk != null){ boolean didInteraction = grandExchangeClerk.interact("Exchange"); return new ConditionalSleep(1000){ @Override public boolean condition() throws InterruptedException { return didInteraction && isOpen(); } }.sleep(); } return false; } return true; } private boolean withdrawCash() throws InterruptedException { if(inventory.getAmount(995) >= 10000){ return true; } if(bank.open()){ boolean success = new ConditionalSleep(1000){ @Override public boolean condition() throws InterruptedException { return bank.isOpen(); } }.sleep(); if(success){ if(bank.getAmount(995) > 0){ return bank.withdraw(995, Bank.WITHDRAW_ALL) && bank.close(); } } } return false; } } Stack trace: java.lang.NullPointerException at org.osbot.rs07.api.GrandExchange.iiIIIiiIIIII(se:202) at org.osbot.rs07.api.GrandExchange.isOpen(se:131) at Util.GrandExchangeUtil.GrandExchangeOperations.openGE(GrandExchangeOperations.java:220) at Util.GrandExchangeUtil.GrandExchangeOperations.priceCheckItemMargin(GrandExchangeOperations.java:45) at Util.Margins.findPrimaryIngredientMargin(Margins.java:150) at Util.Margins.findSpecificConversionMargin(Margins.java:69) at Util.Margins.findAllConversionMargins(Margins.java:96) at Nodes.GENodes.InitialBuy.executeNode(InitialBuy.java:20) at Nodes.MarkovChain.MarkovNodeExecutor.executeThenTraverse(MarkovNodeExecutor.java:36) at ScriptClasses.MainScript.onLoop(MainScript.java:47) at org.osbot.rs07.event.ScriptExecutor$InternalExecutor.run(we:242) at java.lang.Thread.run(Thread.java:748)
  20. your probably fine. Honestly I don't even expect you to be banned OK NVM THEN, you seem to know how to bot modestly. Especially since you mix regular gameplay in. Botwatch is designed to ban goldfarming accounts not casual botters. I'm also suspect bans have to do more with ip and account age; newly made accounts are monitored as the goldfarming meta is skewed towards f2p mass sucide farms, and these accounts are ran off VPS or proxies with data center ips. Good luck with 99 fishing and anymore that you wish to bot. Just don't get too bot happy, you end up ruining the game for yourself just as I have 8 years ago on RS2, IMO there no sense of accomplishment when your just running someone else's script.
  21. Did we always have to restart the client even after setting it to fixed? I don't recall this being the case before 2.5.18.
  22. There is probably no way to create an account on 1 ip then immediately do tutorial island on another. What is probably going on is a VPN is used to make the account creation ip the same as the botting ip. Assume you have a VPS, one way to make the creation ip the same as the botting ip is to create the account on the VPS through remote connection. However, you probably don't want to remote view onto your VPS to create an account due to input latency, so instead you setup a VPN on your VPS that you connect to on your home PC. This makes it so that all (or a targeted subset) your internet traffic is routed through your VPS to jagex's servers. You get to create your account without input lag and have that account registered as far as Jagex is concerned on the same ip that you will later be botting on. I think openVPN is the software used to do this. Note that I have never done this, I just think this is how you would do it. GL!
  23. 99 fletching done, with good timing I only had a day of p2p time left. https://imgur.com/qY9sxrx As previously stated, 99 hunting is next, I'll be scripting a salamanders script. You may have seen 3rd party clients paint the status of traps onto the screen. Probably their implementation has a separate thread poll the status of every trap on a loop, relay a message to their canvas painter on status change. I want to do something similar, however instead of the trap polling thread relaying a message to the canvas painter, queue up a corresponding custom event (subclass of Osbot.Event) instances to be executed under onLoop. Basically a producer-consumer relationship between the polling thread(s) and the onLoop thread. It may be simpler to use the "state based scripting pattern" but I want to write this project to play around with multi-threaded programming. The operating systems class I took was garbage as it was easy to earn an A in. The professor reuses old tests AND the old tests were shared with me AND the test is open note. I was only taking the class because it was degree requirement. So obviously it is my fault that my knowledge of concurrent programming does not extend beyond async REST calls and a vague understanding of the application of a mutex to control access to shared memory.
  24. I like how the thread title's date constantly gets updated. Thank you for your diligence.
  25. If you are using mirror mode and you receive the Resizable warning to restart the client try restarting both your mirror mode target AND osbot. Restarting the osbot client alone is not sufficient.
×
×
  • Create New...