TRSObjectV2 Finding & Usage

Learn how to find static objects and interact with them

Author: Loading...

Co-Authors:
Loading

Basic TRSObjectV2 Object Finding Tutorial Using Objects.GetAll

Hello, and welcome to my tutorial on static object finding using TRSObjectV2! You may be wondering: what even ARE TRSObjectV2, and what do they have to do with the object finding process? In order to answer those questions, we first need to discuss Map & Objects, and how to set those crucial variables up.

Map is an instance of TRSMap that is automatically instantiated when you load in SRL-T. TRSMap contains a large deal of the functionality that we need for object finding. However, Map needs to be set up before we can use it. We first need to establish the area(s) our script will be running in. We can get this data by looking at the chunk map created by Mejrs located at:

Mejrs’ Github Chunk Map Page

In this example, I am going to show you how to walk across Varrock from the spot that teleport puts you, walk to the museum and study the map located in the corner in the information booth. On Mejrs’ map, we can see that the two chunks that the script uses are in [50, 54] and [50, 53] (see the green box in the following image).

This isn’t quite enough for our purpose. We want to make sure that there is enough data to compare your current position against. To accomplish this, we will define a TBox that surrounds the tiles we wish to use. In this example, the red box on the image shows us the desired set of chunks required to make sure our script runs smoothly. Due to the coordinate nature of (pretty much everything including) this, we can easily get the box by looking at the top left and bottom right. Our pair of coordinates are

[49, 55] and [51, 52]

We want to save this data into a constant, as we do not want the value to ever change. We will now discuss the type TRSMapChunk:

type
TRSMapChunk = record
   Chunk: TBox;
   Planes: TIntegerArray;
 end;

There are two variables within: Chunk and Planes. Chunk is a box made from two coordinates that stores the variables we just acquired, and Planes contains the different levels in terms of height. We are not going up or down a ladder/staircase so we only have to worry about plane 0 (the overworld/ground level). You can setup your chunk in one of the following ways:

var
 MyChunk: TRSMapChunk;
begin
 MyChunk := [[49, 55, 51, 52], [0]]; // [[Chunk], [Planes]]
 //or
 MyChunk := Chunk([49, 55, 51, 52], 0);
end;

There’s a few more ways you could do this but for now let’s keep things simple.

It is worth noting that the coordinates don’t follow your traditional definition of top left and bottom right. Blame Jagex lol. However, SRL-T is smart and it should reorder top/bottom and left/right the proper way it needs.

Now that we know how to setup a chunk, let’s load it into Map. We are going to do this by calling Map.SetupChunkEx. This method takes a TBox defining the coordinates of the chunk, an array containing the planes you want to load in, and the downscaling desired when generating the webgraph (more on that in the next tutorial). A value of 8 seems to work well for our purposes. Our script will now read:

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

begin
  Map.SetupChunk(Chunk([49, 55, 51, 52], 0), 8);
end.

Next up, we need to define Objects, which requires that Map be set up first. Objects contains a great deal of the static objects located within your loaded map chunk, including their coordinates, their names, a unique ID associated with them, among a great deal of other things. We only want to load up the objects within the chunk that we just defined, or else it would take forever to search through all of the loaded objects! We do this with a simple method called Objects.Setup. This method takes two inputs: a JSON array containing all of the objects loaded into our map, and the walker associated with the map. Map.Objects will give us our objects, and @Map.Walker is the way we pass in our walker. When you do this, our script will look like this:

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

begin
  Map.SetupChunk(Chunk([49, 55, 51, 52], 0), 8);
  Objects.Setup(Map.Objects, @Map.Walker);
end.

We are getting there! If our object is in the Map.Objects array, then we now have access to it. We do this using Objects.GetAll. This method takes the name of an object, or the names of several objects at the same time and returns an array of the matches located within Objects. In order to do this, we first need an array in which to store this data. We will name our InfoBooth, and we will load in any matches to ‘Information booth’. With objects that have unique names, choosing the correct object isn’t much of a problem. However, if you are looking for a ladder or door, you will end up with a lot of matches! Our object is easy because we know there is only one information booth within our chunks. Here is what that looks like:


{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

var
  InfoBooth: Array of TRSObjectV2;

begin
  Map.SetupChunk(Chunk([49, 55, 51, 52], 0), 8);
  Objects.Setup(Map.Objects, @Map.Walker);
  InfoBooth := Objects.GetAll('Information booth');

  if Length(InfoBooth) > 0 then
  begin
    WriteLN 'InfoBooth contains matches!';
  end;

end.

I immediately check the length of our array to confirm our object loaded into our array. Because we know that there is only one information booth within our chunks, we know that InfoBooth[0] contains our object. We will store this array entry into its own object so we can manipulate it for this tutorial and the next ones coming up. After creating a new variable and assigning it the value of InfoBooth[0], we have done the hard part!

At this point, we will call WalkClick on our object to walk to and click our booth! Here is what the code looks like now:

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

var
  InfoBooth: Array of TRSObjectV2;
  ActualBooth: TRSObjectV2;

begin
  Map.SetupChunk(Chunk([49, 55, 51, 52], 0), 8);
  Objects.Setup(Map.Objects, @Map.Walker);
  InfoBooth := Objects.GetAll('Information booth');

  if Length(InfoBooth) > 0 then
  begin
    WriteLN 'InfoBooth contains matches!';
    ActualBooth := InfoBooth[0];

    ActualBooth.WalkClick(True, 10); //WalkClick(leftclick: Boolean; attempts: Int32)
  end;
end.

..and there you have it! If you are anywhere within those chunks we defined earlier (and you are not trapped behind any doors), you can run this script and it will walk to and click the information booth!

I will go more in depth about loading multiple chunks, making a simple method to filter matches easier, defining auto-color variables, and defining custom objects in the next few sections on TRSObjectV2. Thank you for your time, and happy botting!

Positioning, Multiple Chunks, Refining GetAll Output, Path Walking and WebWalk

Welcome to the second part of our TRSObjectV2 tutorial! The goals here are to learn how to load multiple chunk chunks into Map, become comfortable with Map’s positioning system, defining custom paths to walk through, how to webwalk to a given tile, and to refine the output generated by Objects.GetAll. Let’s get to it! In the previous tutorial, we made a simple script to walk to an object with a unique name. We set up Map using a single TBox defining the area around which we wish to navigate and load objects. For a refresher, here is that script:

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

var
  InfoBooth: Array of TRSObjectV2;
  ActualBooth: TRSObjectV2;

begin
  Map.SetupChunk(Chunk([49, 55, 51, 52], 0), 8);
  Objects.Setup(Map.Objects, @Map.Walker);
  InfoBooth := Objects.GetAll('Information booth');

  if Length(InfoBooth) > 0 then
  begin
    WriteLN 'InfoBooth contains matches!';
    ActualBooth := InfoBooth[0];

    ActualBooth.WalkClick(True, 10);
  end;
end.

In this previous script, we set up Map using the method SetupChunkEx, into which we pass the TBox that defines our chunk. We also pass in a TintegerArray called Planes, which defines the different levels that a chunk contains within itself. Plane 0 refers to the ground level, plane 1 would be up one ladder from ground, plane 2 would be one ladder from plane 1, etc. If you need to access those higher planes, then you will change the array from [0] to [0, 1] or [0, 1, 2] if you need the next higher one too. For most uses, plane 0 will be sufficient. For dungeons - like the one we will be using in this example - if you scroll up on Mejrs’ map into the black screen area, you will be able to find all of the dungeon chunks.

Mejrs’ Github Chunk Map Page

The most difficult part is finding the right dungeon, but if you are patient you will find it! For this tutorial, I will utilize two TRSMapChunks: one for upper Falador/Ice mountain and one for the Dwarven Mine. I will pass both of these into our new method, SetupChunksEx (emphasis on the s) which takes an array of TBoxes representing the different chunks you are loading into your script. I am also going to rename InfoBooth and ActualBooth to AllTrapdoors and ActualTrapdoor, respectively, for later use. This is what that looks like:

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

const
  FAL_CHUNK: TRSMapChunk = [[45, 55, 47, 51], [0]]; // [[Chunk], [Planes]]
  DWV_CHUNK: TRSMapChunk = [[45, 154, 48, 150], [0]]; // [[Chunk], [Planes]]

var
  AllTrapdoors: Array of TRSObjectV2;
  ActualTrapdoor: TRSObjectV2;

begin
  Map.SetupChunksEx([FAL_CHUNK.Chunk, DWV_CHUNK.Chunk], [0], 8);
  Objects.Setup(Map.Objects, @Map.Walker);
end.

This will once again load in all the data in the new chunks. This is really fast, and only happens when you load a new area. We will now learn about positioning. When we load in chunks - if we are inside of those chunks ingame - Map will be able to give us our current position. When standing where Falador teleport takes you, we can find exactly which tile we are standing on. This is as simple as calling

  WriteLN(Map.Position);

which will print the raw TPoint data representing our position. We can easily make a path finding tool by throwing that call into a repeat until loop with a delay:

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

const
  FAL_CHUNK: TRSMapChunk = [[45, 55, 47, 51], [0]]; // [[Chunk], [Planes]]
  DWV_CHUNK: TRSMapChunk = [[45, 154, 48, 150], [0]]; // [[Chunk], [Planes]]

var
  AllTrapdoors: Array of TRSObjectV2;
  ActualTrapdoor: TRSObjectV2;

begin
  Map.SetupChunksEx([FAL_CHUNK.Chunk, DWV_CHUNK.Chunk], [0], 8);
  Objects.Setup(Map.Objects, @Map.Walker);

  repeat
    WriteLN(Map.Position);
    Wait(5000);
  until(False)

end.

This script will print out our position every 5 seconds, forever, until you stop the program. For each tile you move, you have to add or subtract 4 because each tile equals 4 pixels in the collision map. You can make an array of the TPoints generated by this script containing the tiles you want the walker to walk (a path), and you can use Map’s walker to walk the path you want. For example, this script defines a path to walk, and calls Map.Walker.WalkPath to walk that path.

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

const
  FAL_CHUNK: TRSMapChunk = [[45, 55, 47, 51], [0]]; // [[Chunk], [Planes]]
  DWV_CHUNK: TRSMapChunk = [[45, 154, 48, 150], [0]]; // [[Chunk], [Planes]]

var
  AllTrapdoors: Array of TRSObjectV2;
  ActualTrapdoor: TRSObjectV2;
  OurPath: TPointArray; //This is an array of TPoints representing our path
  I, II: Integer;

begin
  Map.SetupChunksEx([FAL_CHUNK.Chunk, DWV_CHUNK.Chunk], [0], 8);
  Objects.Setup(Map.Objects, @Map.Walker);

  OurPath := [[7972, 36629],[7972, 36599],[7972, 36569],[7972, 36539],[7972, 36509]]; //Arbitrary points generated for this example

  Map.Walker.WalkPath(OurPath, 0, False);
end.

If you only know the coordinates of the place you wish you walk, and are not interested in walking a path, you can use Map.Walker.WebWalk to do so. When you load in a chunk, a web of connected points is generated based on the chunk’s collision geometry that allows walking within any area you have defined in your SetupChunksEx. Here is how it is used:

Map.Walker.WebWalk(destination:TPoint; waitUntilDistance: Int32; pathRandomness: Double; debug: Boolean): Boolean;

Destination is our destination, waitUntilDistance is how far away from the destination do we want to exit the walking procedure, pathRandomness is a value from 0 to 1 that randomizes the path taken, and debug spits out debug information if you make it true. If we want to walk to the point [7972, 36629], we would type in:

  Map.Walker.WebWalk([7972, 36629], 0, 0.5, False); //I used 0.5 arbitrarily

When we first loaded in Map, we used a value of 8 for the downscaling variable. This directly affects the amount of detail generated for the webwalk procedures. Experiment with this number if you are having issues with walking, especially within enclosed places like dungeons. When creating a script, having our position so readily available is quite useful. It will be especially useful for the next segment.

In order to walk to the trapdoor leading to the Dwarven Mine, we need to know which trapdoor to walk to in the first place (in case there are multiple). This next step requires that you have run the script at least once, in order to generate the object data we need to proceed.

Looking at Mejrs’ map, we can see that the trapdoor we want is located in the chunk [47, 53]. When I stand next to the trapdoor and run the script that repeatedly writes your position, I get the point [7972, 36629] or something closeish to that. Each object stores its coordinates - sometimes several coordinate pairs if there are multiple of that object like ladders – so we want to find out where our trapdoor is. We will identify it using our Map.Position coordinates, and then save it like we did for our information booth before. In order to do that, we need to go digging into some data.

Open Simba, and open the following directory: C:\Users\YOUR_PC_USERNAME_HERE\AppData\Local\Simba\Data\cache\map, open the newest folder in that directory, then navigate to the objects folder. Switch the filetype in the bottom-right corner of the open file dialog to All Files and then open file “47-53.json”. This file contains all of the object data that was cached. Be aware, not all objects are in this cache! If your object isn’t here, then the next tutorial on custom objects and Finder usage is for you! Back to the file: All of the text will be in a single line, which we can fix by clicking Tools>Format script in the navigation bar. A quick CTRL+F search for Trapdoor shows that we have a trapdoor with data “coordinates”:[[7982,36630]]. We can compare them to our known position and see that they are extremely close to each other. Keep this tab open for reference.

We are now going to GetAll like we did in the last tutorial, but this time we are going to iterate through each entry of its output (even if it is only 1). I am going to compare the coordinates of each object returned by GetAll to the known coordinate of the trapdoor we want to use. You can use the ID datafield as well to determine the correct object for finding, but I am only doing coordinates for simplicity. Here is what iterating through and comparing just the coordinates looks like:

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

const
  FAL_CHUNK: TRSMapChunk = [[45, 55, 47, 51], [0]]; // [[Chunk], [Planes]]
  DWV_CHUNK: TRSMapChunk = [[45, 154, 48, 150], [0]]; // [[Chunk], [Planes]]

var
  AllTrapdoors: Array of TRSObjectV2;
  ActualTrapdoor: TRSObjectV2;
  I, II: Integer;

begin
  Map.SetupChunksEx([FAL_CHUNK.Chunk, DWV_CHUNK.Chunk], [0], 8);
  Objects.Setup(Map.Objects, @Map.Walker);

  AllTrapdoors := Objects.GetAll('Trapdoor');

  for I := 0 to High(AllTrapdoors) do  //Iterate through each object
    for II := 0 to High(AllTrapdoors[I].Coordinates) do //Iterate through every coordinate pair of current object
      if AllTrapdoors[I].Coordinates[II] = Point(7982, 36630) then //Check against known coordinates
        ActualTrapdoor := AllTrapdoors[I]; //Assign correct object entry to our ActualTrapdoor variable

As in the previous tutorial, we can call

ActualTrapdoor.WalkClick(leftclick: Boolean; attempts: Int32);

and as long as you are within your defined chunks, it will webwalk to the trapdoor and click on it. There are many things you can do with an object, such as hovering over it, getting the raw TPoint data from the finder, clicking without walking.. Experiment with it! In this case, we will right click on the trapdoor this time by changing leftclick to false when we call WalkClick, and then we will use a new variable called ChooseOption to select the right option to climb down. We will also print our position before we WalkClick to the trapdoor, and then once again when we are in the mine. This is to demonstrate how wildly different the coordinates are between dungeons and their overworld counterparts. Our finished script looks like this!

{$I SRL-T/osr.simba}
{$I WaspLib/osr.simba}

const
  FAL_CHUNK: TRSMapChunk = [[45, 55, 47, 51], [0]]; // [[Chunk], [Planes]]
  DWV_CHUNK: TRSMapChunk = [[45, 154, 48, 150], [0]]; // [[Chunk], [Planes]]

var
  AllTrapdoors: Array of TRSObjectV2;
  ActualTrapdoor: TRSObjectV2;
  I, II: Integer;

begin
  Map.SetupChunksEx([FAL_CHUNK.Chunk, DWV_CHUNK.Chunk], [0], 8);
  Objects.Setup(Map.Objects, @Map.Walker);

  AllTrapdoors := Objects.GetAll('Trapdoor');

  for I := 0 to High(AllTrapdoors) do  //Iterate through each object
    for II := 0 to High(AllTrapdoors[I].Coordinates) do //Iterate through every coordinate pair of current object
      if AllTrapdoors[I].Coordinates[II] = Point(7982, 36630) then //Check against known coordinates
        ActualTrapdoor := AllTrapdoors[I]; //Assign correct object entry to our ActualTrapdoor variable

  WriteLN(Map.Position); //Print our position in the overworld

  ActualTrapdoor.WalkClick(False, 5);

  if ChooseOption.IsOpen(2000, 50) then //If our right click menu opens in 2000 ms (checking every 50ms) then
    ChooseOption.Select('Climb-down', MOUSE_LEFT, False, True); //Select the correct option, clicking with left mouse,
                                                                //ignoring case and closing if it can't find the option
  WriteLN(Map.Position); //Print our position now that we are in the mine
end.

That’s it for this one! In the next section, I will cover custom object creation and definition, auto-coloring for very precise object finding, debugging objects, and a few more things we can do with TRSObjectV2! Thank you for your time, and happy botting!

..coming soon..