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 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 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
New container structure traversing in C#
Page 1 of 4 123 ... LastLast
Results 1 to 10 of 34

Thread: New container structure traversing in C#

  1. #1

    New container structure traversing in C#

    Here is simplified piece of my code in C# used to traverse new containers structure in Tibia - with example reading the name of container. It is "the smart way" of traversing containers, not brute-force - this will take the minimum ammount of time to traverse it and find needed container. Hope it is clear enough to make use of this.

    PHP Code:
    private static uint at(long addr)
    {
        return 
    TibiaControl.Client.Memory.ReadUInt32(addr);
    }
        
    public static 
    String _getContainerName(int contId)
    {
        
    uint ptr at(TibiaCore.Addresses.Container.Pointer);
        
    ptr at(ptr 0x08);
        
    uint next at(ptr 0x04);

        
    bool found false;
        
    bool lastNode false;

        while (!
    lastNode && !found)
        {
            
    uint cid at(next 0x0C);

            if (
    contId cid)
                
    next at(next 0x00);
            else if (
    contId cid)
                
    next at(next 0x08);
            else
                
    found true;

            if (
    next == ptr)
                
    lastNode true;
        }
        
        if (
    found)
        {
            
    uint container at(next 0x10);
            
            const 
    uint offsetName 0x20;
            
            
    String name TibiaControl.Client.Memory.ReadString(container offsetName);
            return 
    name;
        }
        else
            return 
    null;


  2. #2
    Senior Member
    Join Date
    Jan 2008
    Location
    Cambridge, England
    Posts
    725
    Looks good mate, short and sweet, just as I like. Your naming conventions are a bit slack (e.g use of contId and cid - cid is normally interpreted here as CreatureID, though I believe in this instance it is container ID), but that's easily beatable by either ignoring it or just find replacing. Thanks for sharing, really appreciate it

  3. #3
    Junior Member
    Join Date
    Oct 2011
    Posts
    6
    Maybe i did something wrong while i was testing your script but, while trying to read "Backpack of Holding"'s name it returns strange symbols or sometimes nothing.

    Until now every other container returns it's names.


    Apparently doesn't read Brocade Backpack too.
    Last edited by Leamself; 07-22-2013 at 11:47 PM.

  4. #4
    Yea, if name is longer than x (dont remember, 10?) characters, this function wont work, i forgot about that. At container + offsetName then is one more pointer, that points to the name.

    You must do the following trick (or any other way of checking if it is an pointer there you find):

    Change:
    PHP Code:
            String name TibiaControl.Client.Memory.ReadString(container offsetName); 
    to:
    PHP Code:
            String name;
            
    byte test TibiaControl.Client.Memory.ReadByte(container offsetName 0x03); // reading - third byte for test purposes
            
    if (test 0x20 && test 0x00// there is pointer at 99.9%  there
            
    {
                    
    uint namePtr TibiaControl.Client.Memory.ReadUInt32(container offsetName);
                    
    name TibiaControl.Client.Memory.ReadString(namePtr);
            }
            else 
    // there is string
                    
    name TibiaControl.Client.Memory.ReadString(container offsetName); 
    This is really work-around way, and probably there is bool value or someting like that indicating if at given address is one more pointer, or just string with name, but this make it for me and i didn't find it fail anytime yet. If You find smarter way of doing this, please feel free to post, i would appreciate this.

    @Sketchy

    Thanks, that is the proper,smart way i was looking for.
    Last edited by MeNi; 07-23-2013 at 09:41 AM.

  5. #5
    Senior Member
    Join Date
    Sep 2007
    Posts
    230
    They are actually storing as a std::string which in their compiler version (VC++ 2010) has a 28-byte memory structure as follows:

    PHP Code:
    struct STDString
    {
        
    union
        
    {
            
    char Chars[16];
            
    charPointer;
        } 
    Text;
        
        
    uint32_t Length;
        
    uint32_t Capacity;
        
    uint32_t Unused;

    Basically it will use the Text.Chars buffer at first if the initial string will fit, if not a new buffer will be allocated with a pointer to it being stored in Text.Pointer which occupies the same memory as the first 4 bytes of Text.Chars. The Capacity field contains the maximum number of characters, minus 1 for the NULL terminator, the current buffer can hold which is used to determine whether to use Text.Chars (Capacity <= 15) or Text.Pointer (Capacity >= 16). So you should do something like:

    PHP Code:
    uint namePtr container offsetName;
    if (
    TibiaControl.Client.Memory.ReadInt32(namePtr 20) > 15// Reads Capacity field which is at byte 20
    {
        
    namePtr TibiaControl.Client.Memory.ReadUInt32(namePtr);
    }
    string name TibiaControl.Client.Memory.ReadString(namePtr); 

  6. #6
    Senior Member
    Join Date
    Jan 2012
    Posts
    417
    Quote Originally Posted by XtrmJash View Post
    Looks good mate, short and sweet, just as I like. Your naming conventions are a bit slack (e.g use of contId and cid - cid is normally interpreted here as CreatureID, though I believe in this instance it is container ID), but that's easily beatable by either ignoring it or just find replacing. Thanks for sharing, really appreciate it
    those local variables he has named "contId" and "cid" are not containers id as we are used to, based on the offsets he's reading from, they are "index" of the given backpack in the tree.

  7. #7
    Senior Member
    Join Date
    Dec 2011
    Posts
    249
    My "bruteforcing" method in Cheat Engine's Lua scripter to get all containers

    Code:
    function findContainer(table, container) --Substitute for C# Linq
       for _, c in pairs(table) do
           if container.index == c.index then
              return true
           end
       end
       return false
    end
    
    function getContainers()
    
       local containerPointer = 0x5E72C0 + getAddress("Tibia.exe")
       local containerList = {} --List<Container> containerList = new List<Container>();
       local tries = 0
       local ptr = readInteger(containerPointer)
       local amount = readInteger(ptr + 0xC)
    
       ptr = readInteger(readInteger(ptr + 0x8))
    
       if amount > 0 then
          local adder = 0x8
          while #containerList ~= amount do
                local container = {
                                    index = readInteger(readInteger(ptr + 0x10)), 
                                    name = readString(readInteger(ptr + 0x10) + 0x20, 30),
                                    id = readInteger(readInteger(ptr + 0x10) + 0xC),
                                    volume = readInteger(readInteger(ptr + 0x10) + 0x40)
                                  }
                if container.name and not findContainer(containerList, container) then
                   tries = 0
                   table.insert(containerList, container)
                else
                    tries = tries + 1
                end
    
                if tries < 5 then
                    adder = adder == 0x8 and 0 or adder + 0x4
                else
                    adder = 0x8
                end
    
                ptr = readInteger(ptr + adder)
          end
       end
       return containerList
    end
    
    for k,v in pairs(getContainers()) do
        print("Name: " .. v.name)
        print("Index: " .. v.index)
        print("Id: " .. v.id)
        print("Volume: " .. v.volume)
        print("-----------")
    end

  8. #8
    Senior Member
    Join Date
    Jan 2012
    Posts
    417
    Quote Originally Posted by ottizy View Post
    My "bruteforcing" method in Cheat Engine's Lua scripter to get all containers
    I'm glad someone other than me uses cheat engine's scripting interface.

    After reading your code, I realized that all the solutions (using ReadProcessMemory) loop through offsets 0x0, 0x4 and 0x8, which highly enforces the "tree" theory, also mentioned by Dayle in the previous thread and Stiju (std::map in its internal uses "red-black tree" if I'm not wrong), as left, parent, right in a order I don't know. Also, MeNi's solution uses a comparison on the container's index, which I tried several times, but always led me to false positives after closing/reopen containers when we have something like 16 containers open.

    MeNi did in a way that I had not tried, but seems quite ellegant how he loops to find a single container (a bit risky of getting an infinite loop).

    Anyway, would be interesting to see MeNi's loop to grab all the containers like you did.

  9. #9
    Senior Member
    Join Date
    Dec 2011
    Posts
    249
    Quote Originally Posted by Blequi View Post
    I'm glad someone other than me uses cheat engine's scripting interface.

    After reading your code, I realized that all the solutions (using ReadProcessMemory) loop through offsets 0x0, 0x4 and 0x8, which highly enforces the "tree" theory, also mentioned by Dayle in the previous thread and Stiju (std::map in its internal uses "red-black tree" if I'm not wrong), as left, parent, right in a order I don't know. Also, MeNi's solution uses a comparison on the container's index, which I tried several times, but always led me to false positives after closing/reopen containers when we have something like 16 containers open.

    MeNi did in a way that I had not tried, but seems quite ellegant how he loops to find a single container (a bit risky of getting an infinite loop).

    Anyway, would be interesting to see MeNi's loop to grab all the containers like you did.

    It's a great way to test structures and other stuff, although quite annoying that readInteger returns nil if the pointer is invalid

  10. #10
    Senior Member
    Join Date
    Jan 2012
    Posts
    417
    I wrote an console application (C#) as sample to my "bruteforcing" method.

    http://pastebin.com/6sJXa0S0

    The core of the code are the layout of the structures involved and especially the ContainersHandler class.

    The idea is loop through what I called "CONTAINER_NODE" going to "Left", "Center", "Right" -> "offset 0", "offset 0x4", "offset 0x8" and using a hash set to prevent read a container already read.

    Disregard the "Reading Memory" stuff if you want, because I was just practicing around a bit with p/invoke. I made all this layout via structs to prevent unnecessary ReadProcessMemory calls, because p/invoke kills .NET performance.

    If someone want, I can upload the project I've created for this sample.

Posting Permissions

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