Welcome to TRiBot Forums

Register now to gain access to all of our features. Once registered and logged in, you will be able to contribute to this site by submitting your own content or replying to existing content. You'll be able to customize your profile, receive reputation points as a reward for submitting content, while also communicating with other members via your own private inbox, plus much more! This message will be removed once you have signed in.

Sign in to follow this  
Followers 0
botsallday

Simple filters tutorial (Code snippets included)

5 posts in this topic

Filters Tutorial
 
What are filters used for?
Filters allow you to separate the contents of your variables into groups that comply with a certain condition (or set of conditions). 
 
Why use filters?
Filters make writing some complex pieces of code substantially shorter and much simpler. An example would be if we wanted to detect cannons, and hop if it was in our combat area. There are surely multiple ways of doing this without filters, but here is an example of how easily it can be done with filters.
 
private boolean detectCannon() {    // get cannons using a name filter    RSObject[] cannon = Objects.find(20, Filters.Objects.nameContains("Dwarf multi"));    // I use 20 for the distance above, but using this method it is better to be too high than too low.    // null check to avoid null pointer execeptions    if (cannon.length > 0) {       // iterate cannons so that we don"t just check the first one       for (int i = 0; i < cannon.length; i++) {          // ensure they are in the same area we are killing crabs in          if (BADAreas.EAST_ROCK_CRABS_AREA.contains(cannon[i].getPosition())) {              return true;          }       }    }    return false;}

The method above isnt terrible, but we can do even better with filters!
private boolean detectCannon() {     // instead of iterating all of the cannons and checking their areas, we can instead use a filter to only fetch cannons that are in our area    RSObject[] cannon = Objects.find(20, Filters.Objects.nameContains("Dwarf multi").combine(Filters.Objects.inArea(COMBAT_AREA), true));     // if we have any cannons at this point then we should hop because we know it is in fact a cannon and it is also in our area     if (cannon.length > 0) {          return true;     }     return false;}

We could make it even more elegant, but I personally prefer the above for readability

private boolean detectCannon() {     // we return an expression which will evaluate to true if any cannons exist in our combat area or false if they do not     return Objects.find(20, Filters.Objects.nameContains("Dwarf multi").combine(Filters.Objects.inArea(COMBAT_AREA), true)).length > 0;}
 
When should you use filters?
The shortest answer here is as often as possible. If using a filter is possible in your situation, then it is most likely going to be more efficient than any other method you would use to achieve the same end result. Use them at will.
 
Further examples and scenarios -
A situation I find myself in often enough when writing scripts is that I need to find some objects, but I don"t actually know the name (or ID) of the object ahead of time. I will use a simplified scenario to explain the point. In this scenario we need to determine if any food is in the inventory. We do not know (or care) about the name. We just want to determine if there is anything in the inventory that we can eat.
private boolean hasFoodInInventory() {    // use filters to get inventory items that we can eat    RSItem[] foods = Inventory.find(Filters.Items.actionsContains("Eat"));    // see if we have results    if (foods.length > 0) {        // eat the foods        return true;    }    return false;}


That works for most cases, but since our users will inevitably do crazy things we can do better.

private boolean hasFoodInInventory() {     // use filters to get inventory items we can eat that aren"t rock cakes (Rock cakes kill you when eaten)     RSItem[] foods_that_dont_kill_us = Inventory.find(Filters.Items.actionsContains("Eat").combine(Filters.Items.nameNotContains("ock cake"), true));     // see if we have results     if (foods_that_dont_kill_us.length > 0) {         return true;     }     return false;}

 
Another situation where filters have proven very useful for me is when I need to find items that have slightly different names as they change. An example of such items would be potions. They go from "Potion (4)" to "Potion (3)" etc... Filters can make it very easy to find potions within your inventory. For this example suppose we want to find any of our potions from our inventory.
private boolean hasDrinkablePotions() {    // use filters to get attack and strength potions from the inventory regardless of the doses left    RSItem[] potions = Inventory.find(Filters.Items.nameContains("ttack", "rength").combine(Filters.Items.actionsContains("Drink"), true));    if (potions.length > 0) {        return true;    }    return false;}


 

I am fairly new to filters myself, but I have used them quite a bit already. If you notice a better way of doing anything I have gone over please do share it and I will update the post. If there is anything you think I should add then feel free to let me know!
 
 
EDITS : 
  • As shown below, the methods from the tutorial can be modified to be dynamic and reusable. If you plan to use this method in your code/api, I would suggest using this version as it is shorter and can be re-used. (USA & ineu)
  • private boolean isObjectInArea(final String name, final RSArea area) {    return Objects.find(20,         Filters.Objects.nameEquals(name).combine(Filters.Objects.inArea(area), true)).length > 0;}
Edited by botsallday
1 person likes this

Share this post


Link to post
Share on other sites

Great tutorial!
Really well organized with lots of good examples for real life use.

Thanks for putting the time in to write this up!

Share this post


Link to post
Share on other sites

Good examples, but eliminating redundancy doesn't have to sacrifice readability!

private boolean isObjectInArea(String $objectName) {    RSObject[] $object = Objects.find(20,         Filters.Objects.nameContains($objectName).combine(            Filters.Objects.inArea(LOCAL_AREA), true));    return ($object.length > 0);}

EDIT: Modified your method a little bit

Edited by ineu

Share this post


Link to post
Share on other sites

Good examples, but eliminating redundancy doesn't have to sacrifice readability!

private boolean isObjectInArea(String $objectName) {    RSObject[] $object = Objects.find(20,         Filters.Objects.nameContains($objectName).combine(            Filters.Objects.inArea(LOCAL_AREA), true));    return ($object.length > 0);}

EDIT: Modified your method a little bit

	private boolean isObjectInArea(final String name, final RSArea area) {		return Objects.find(20,				Filters.Objects.nameEquals(name).combine(Filters.Objects.inArea(area), true)).length > 0;	}
2 people like this

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0

  • Recently Browsing   0 members

    No registered users viewing this page.