Deprecated: The behavior of unparenthesized expressions containing both '.' and '+'/'-' will change in PHP 8: '+'/'-' will take a higher precedence in /home/iano/public_html/tpforums-vb5/forum/includes/class_core.php on line 5842

PHP Warning: Use of undefined constant MYSQL_NUM - assumed 'MYSQL_NUM' (this will throw an Error in a future version of PHP) in ..../includes/init.php on line 165

PHP Warning: Use of undefined constant MYSQL_ASSOC - assumed 'MYSQL_ASSOC' (this will throw an Error in a future version of PHP) in ..../includes/init.php on line 165

PHP Warning: Use of undefined constant MYSQL_BOTH - assumed 'MYSQL_BOTH' (this will throw an Error in a future version of PHP) in ..../includes/init.php on line 165

PHP Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in ..../includes/functions_navigation.php on line 588

PHP Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in ..../includes/functions_navigation.php on line 612

PHP Warning: Use of undefined constant misc - assumed 'misc' (this will throw an Error in a future version of PHP) in ..../global.php(29) : eval()'d code(6) : eval()'d code on line 1

PHP Warning: Use of undefined constant index - assumed 'index' (this will throw an Error in a future version of PHP) in ..../global.php(29) : eval()'d code(6) : eval()'d code on line 1

PHP Warning: Use of undefined constant misc - assumed 'misc' (this will throw an Error in a future version of PHP) in ..../includes/class_bootstrap.php(1422) : eval()'d code(4) : eval()'d code on line 1

PHP Warning: Use of undefined constant index - assumed 'index' (this will throw an Error in a future version of PHP) in ..../includes/class_bootstrap.php(1422) : eval()'d code(4) : eval()'d code on line 1

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 85

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 85

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6

PHP Warning: Use of undefined constant onlinestatusphrase - assumed 'onlinestatusphrase' (this will throw an Error in a future version of PHP) in ..../includes/class_core.php(4684) : eval()'d code on line 6
Optimzing map reading
Page 1 of 3 123 LastLast
Results 1 to 10 of 28

Thread: Optimzing map reading

  1. #1
    Super Moderator
    Join Date
    May 2007
    Posts
    1,191

    Optimzing map reading

    Before reading this, I assume you have at least some knowledge about the map structure. It's preferable that you have read vanitas' article on map reading over at tibiaauto.net (archived link here: http://web.archive.org/web/201201291...t_mapread.html).

    Currently the way bots and other tools read the map is quite inefficient, i.e. to read the player tile most, if not all, code out there uses a bruteforce tactic; read all available tiles until the player is found.
    Today I will show you how to read tiles in a smarter way, using information that haven't been discovered yet as far as I know.

    It all starts with a pointer, which for the current version of Tibia (9.81) can be found at 0x005DA5E0 (+ base address).
    This pointer points to a structure containing tile numbers. These tile numbers change as the player moves, effectively removing any necessities for centralizing memory locations and heavily reducing the amount of WinAPI calls necessary to find the same information.

    The structure contains 2016 unsigned integers, exactly how many tiles there are in the map structure.
    The player's tile can always be found at the 116th tile of a floor. Keep in mind that each tile number in this structure is 4 bytes long.
    Here's a snippet to find it:
    Code:
                uint id = this.Client.Player.ID;
                int address = this.Client.Memory.ReadInt32(this.Client.Addresses.Map.TileNumberPointer);
                for (int i = 0; i < this.Client.Addresses.Map.MaxZ; i++)
                {
                    int tileNumber = this.Client.Memory.ReadInt32(address +
                        (this.Client.Addresses.Map.MaxTilesPerFloor * i * 4) +
                        this.Client.Addresses.Map.TileNumberOffsetCenter);
                    Objects.Tile t = this.CachedTiles[tileNumber];
                    t.UpdateObjects();
                    if (!t.ContainsCreature(id)) continue;
                    t.WorldLocation = this.Client.Player.Location;
                    t.RealMemoryLocation = this.TileNumberToMemoryLocation(t.TileNumber, t);
                    t.MemoryLocation = this.CentralizeMemoryLocation(t.RealMemoryLocation, t);
                    return t;
                }
    Doing this reduces the max amount of tiles read from 2016 to 8. Quite an improvement!

    Using the information described in vanitas' article, you can also get world locations and tiles other than the player's through this.
    Happy hacking!

  2. #2
    Super Moderator klusbert's Avatar
    Join Date
    Dec 2007
    Posts
    1,201
    You will save so much time using this, instead of a 2016 big long loop now do a 8 long loop.
    See my image if you do not believe me :P

    This is going into tibiaAPi now
    Once again great job!
    Attached Images Attached Images
    How to find battlelist address --> http://tpforums.org/forum/thread-8146.html
    Updating addresses --> http://tpforums.org/forum/thread-8625.html
    DataReader --> http://tpforums.org/forum/thread-10387.html

  3. #3
    Administrator
    Join Date
    Mar 2007
    Posts
    1,723
    I always thought there had to be an easier way, nice job. How'd you come to find this structure/pointer?

  4. #4
    Super Moderator
    Join Date
    May 2007
    Posts
    1,191
    Quote Originally Posted by Jo3Bingham View Post
    I always thought there had to be an easier way, nice job. How'd you come to find this structure/pointer?
    I knew there was something related to the player's tile in the older clients, and as I play RealOTS (7.72), I had a go with finding something.
    I didn't find what I was looking for, instead I found this. For the better I suppose.

  5. #5
    Senior Member
    Join Date
    Jan 2012
    Posts
    417
    Great find Blaster_89.

    I was mentioning exactly to it on this post http://tpforums.org/vbulletin/showth...ll=1#post49228 some time ago. Since you got 90% of the work done, if you want I can explain the complete way to each available tile on Tibia's memory.

    I guess DarkstaR knew it too because this post http://forums.xenobot.net/showthread...l=1#post117011

  6. #6
    Super Moderator
    Join Date
    May 2007
    Posts
    1,191
    Quote Originally Posted by Blequi View Post
    Since you got 90% of the work done, if you want I can explain the complete way to each available tile on Tibia's memory.
    Sure, the more information there is floating around, the better!

  7. #7
    Senior Member
    Join Date
    Jan 2012
    Posts
    417
    Ok, since you lifted the flag, here we go:

    Quote Originally Posted by Blaster_89
    This pointer points to a structure containing tile numbers. These tile numbers change as the player moves, effectively removing any necessities for centralizing memory locations and heavily reducing the amount of WinAPI calls necessary to find the same information.
    This structure that you are saying is the tiles array index. Why? As in the beginning vanitas proved, TibiaClient stores map in a 3D array where [z][y][x] = [0..7][0..13][0..17].

    If you do a nested loop in the array you've found, i.e.,
    Code:
    for z = 0, 7 do
       for y = 0, 13 do
          for x = 0, 17 do
    you'll face only 2 behaviors, your tile will match at [7 - Self.Z, 6, 8] when Self.Z <= 7 and [2, 6, 8] otherwise.

    So, to get your own tile is a O(1) operation

    And is really suggestive that we stands Y = 6, X = 8... because it's really center of the X, Y coordinates. What I founded to be odd when coding it, was the fact that if
    we match ourself at [2, 6, 8] if Self.Z > 7. So what happens when Self.Z > 13 and we want tiles at Z = 15?

    ex:
    Suppose Self.Z = 14 and we want Z = 15.
    if we match ourself at [2, 6, 8], the logic says Z = 15 is at [1, Y, X], and what is stored at 0? Simple. Nothing (it means tiles at [0, Y, X] will have 0 as count of items). I checked on Thais, there is a hidden city at Z = 15.

    Arises at least 3 functions to be coded:

    • Get Self Tile
    • Get Tile on x, y, z
    • Get All Tiles in a single function


    The first is really easy, because it is only:

    tile = read(mapStart + read(indexArray[7 - Self.Z, 6, 8]) * mapStep) if Self.Z <= 7 or read(mapStart + read(indexArray[2, 6, 8]) * mapStep) otherwise

    Lasts 2 is just matter of writing a nice way to offset things and I'll paste directly from my bot here (don't worry, I'll explain first):

    In the following, my Tile constructor is "Tile(int index, int x, int y, int z)" or "Tile(int index, Location)", Addresses.TILE_INDEX_INT is the array you Blaster_89 found and Addresses.TILE_INDEX_INT[z, y, x] is the index of tile at x, y, z and Addresses.MAP_INT[,] is the structure buffer as int[,] array, better saying Addresses.MAP_INT[i, ] is i-th tile in Tibia memory

    Get Tile on x, y, z:
    Code:
    Tile OnLocation(int x, int y, int z)
    {
                if (z < 0 || z > 15)
                    return null;
    
                Location self = Self.Location;
                Location desired = new Location(x, y, z);
    
                Utils.Update(UpdateStruct.Tiles); // It updates 2 arrays, tiles array and array that Blaster_89 found
                int start, end, aux;
    
                if (self.Z <= 7)
                {
                    start = 7;
                    end = -1;
                }
                else if (self.Z <= 13)
                {
                    start = self.Z + 2;
                    end = self.Z - 3;
                }
                else if (self.Z == 14)
                {
                    start = self.Z + 1;
                    end = self.Z - 3;
                }
                else
                {
                    start = self.Z;
                    end = self.Z - 3;
                }
    
                aux = self.Z - z;
                x -= aux + (self.X - 8);
                y -= aux + (self.Y - 6);
                z = start - z;
    
                if (x < 0 || x >= 18 || y < 0 || y >= 14 || z < 0)
                    return null;
    
                return new Tile(Addresses.TILE_INDEX_INT[z, y, x], desired);
    }
    Get All Tiles
    Code:
    List<Tile> All()
    {
                List<Tile> tiles = new List<Tile>();
    
                int z, y, x, aux, start, end;
                Location self = Self.Location;
    
                Utils.Update(UpdateStruct.Tiles); // It updates 2 arrays, tiles array and array that Blaster_89 found
    
                if (self.Z <= 7)
                {
                    start = 7;
                    end = -1;
                }
                else if (self.Z <= 13)
                {
                    start = self.Z + 2;
                    end = self.Z - 3;
                }
                else if (self.Z == 14)
                {
                    start = self.Z + 1;
                    end = self.Z - 3;
                }
                else
                {
                    start = self.Z;
                    end = self.Z - 3;
                }
    
                for (z = start; z > end; z--)
                {
                    aux = self.Z - z;
                    for (y = aux; y < 14 + aux; y++)
                        for (x = aux; x < 18 + aux; x++)
                            if (Addresses.MAP_INT[Addresses.TILE_INDEX_INT[start - z, y - aux, x - aux], Addresses.TILE_COUNT_ON_STACK_INT] > 0) // if tile has > 0 items, ok
                                tiles.Add(new Tile(Addresses.TILE_INDEX_INT[start - z, y - aux, x - aux], self.X - 8 + x, self.Y - 6 + y, z));
                }
    
                return tiles;
    }
    Probably there is some mistake hidden, but well , that's the life.

    A bit of offtopic: If you or someone want to look for new structures, recently I found the structure that Tibia stores effects and missiles to draw the screen. So, last offset of Tile structure is the index of this new array I've found.

    Ok ok, I'll keep quiet because you Blaster_89 is releasing my secrets!!! Haha, I'm glad someone got it.

    EDIT: I almost forget to mention that:
    when Self.Z <= 7, you have all tiles above you available, i.e, level 0 - 7.
    when Self.Z > 7, you have
    Self.Z - 2, Self.Z - 1, Self.Z, Self.Z + 1, Self.Z + 2 levels availables
    Last edited by Blequi; 02-01-2013 at 02:44 PM. Reason: fixing wrong info

  8. #8
    Super Moderator klusbert's Avatar
    Join Date
    Dec 2007
    Posts
    1,201
    Nice Blequi, what is your bot anyway? private project?
    How to find battlelist address --> http://tpforums.org/forum/thread-8146.html
    Updating addresses --> http://tpforums.org/forum/thread-8625.html
    DataReader --> http://tpforums.org/forum/thread-10387.html

  9. #9
    Senior Member
    Join Date
    Jan 2012
    Posts
    417
    Quote Originally Posted by klusbert View Post
    Nice Blequi, what is your bot anyway? private project?
    yes. 10 char length, writing something

  10. #10
    Senior Member
    Join Date
    Jan 2012
    Posts
    417
    since I coded it long time ago, I posted wrong info at how you catch your character tile, because I was looking right now at my sources and the correct one is:

    Code:
                    Location self = Self.Location
                    int index = 7 - self.Z;
                    index = (index >= 0) ? Addresses.TILE_INDEX_INT[index, 6, 8] : Addresses.TILE_INDEX_INT[2, 6, 8];
    
                    return new Tile(index, self);
    I'll bold updated parts of my post above. I'm saved because in the end I said "Probably there is some mistake hidden, but well , that's the life."

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •