Log in

View Full Version : Tibia 11 - Selected row in Character List - Current progress



blackd
10-04-2016, 10:26
Well, we are stuck here for now. Any extra help would be nice.
Goal: We need a reliable way to determine the selected row in the character list.
Purpose: This small "stupid" part is important for proxy bots, tibiacast and many other software that depends on packets.

This is my current progress:

- I could not find a reliable path that always contain the selector. However, there seems to be a path that works for the first show of the character list:
"Qt5Gui.dll"+00482EE4 > 20 > C > 58 > 4 > F8 > 418
This is not a full solution. However, this path maybe could mean something.
- In a fast look to the assembly code, it looks like the real path must end in
X > 418
or
X > 3DC > 4 > DC
Why? Because if you toggle breakpoint at
Qt5Quick.QQuickMouseEvent::y+91C0
then you can verify both paths are valid while execution is paused at that point:
[EBX+4] > 3DC > 4 > DC
[EBX+4] > 418
The problem is [EBX+4] is overwritten with trash after the execution is resumed. :(
It could be the start of a solution with the help of injection tactics. However I prefer to avoid injection for now.


Some related findings:
I already found a stable way to obtain character list: http://www.blackdtools.net/showthread.php?62978-Tibia-11-Collection-of-server-info-AND-character-list It does not include a way to know selection. However, I guess the selection must be somewhere near that list. We need to investigate around.

I also found a stable way to read Tibia title after login.
adrSelectedCharName="Qt5Core.dll" + 004555C8 > 8 > C > 4 > 18 > 38 > 28
adrSelectedCharName points to a QSTRING with character name. If you are outside game then it will point to null (address FFFFFFF) or to an address containing an empty qstring ""

I also found a way to pause everything in Tibia client using Cheat Engine: Memory View> Debug > Break > Select first thread in the list > OK
Pausing Tibia during char list inspection is great because other way the memory there seems to be changing a lot with each selection change. It also prevents char list window to go away because inactivity.

More facts:
- Somewhere in the memory there seems to be 3 chaotic places that hold the selection color for each row.
F4F4F4FF = COLOR SELECTED
C0C0C0FF = COLOR FOR ROW NOT SELECTED
Search array of bytes in Cheat Engine to discover them. If we can find the structure that links all the color positions then we could obtain selection from the color.

blackd
10-04-2016, 22:20
A new interesting discovery today:
adrSelectedItem_currentScreenPositionY="Qt5Widgets.dll" + 00401DC4 > 70 > 4 > 68
points to a 8 bytes DOUBLE, containing the Y position of the selected row.

More data around:
adrSelectedItem_currentScreenPositionX="Qt5Widgets .dll" + 00401DC4 > 70 > 4 > 60
adrSelectedItem_width="Qt5Widgets.dll" + 00401DC4 > 70 > 4 > a0
adrSelectedItem_height="Qt5Widgets.dll" + 00401DC4 > 70 > 4 > a8

DiegoTV
10-05-2016, 04:09
With the latter you could easily find a way to figure out the SelectedIndex quite easily, don't you think?
I haven't had the time to work around it though I'll try to make some now and post a code snippet if I get it to work :)

blackd
10-05-2016, 10:07
The only problem with the selected item is that it depends on 2 things:
- current client height: You would need to determine current client height and include it in your maths.
- popup Y position: If someone drag and move the Character Selection popup then the selected item position will change too.

Even if you can do proper maths with everything I am afraid this solution will not work after the character list is gone.
For my proxy I need to read selected character between character selection and ingame. I know there must be a way to read current selection in any moment. Other way client would not be able to restore current selection after logout.

blackd
10-09-2016, 14:35
I found a solution that works for me.
This allows to check selected char exactly after user selected a char:

adrSelectedCharName_afterCharList="Qt5Core.dll" + 004555C8 > 8 > 320 > 18 > 60 > 0
adrSelectedServerURL_afterCharList="Qt5Core.dll" + 004555C8 > 8 > 320 > 18 > 60 > 4
adrSelectedServerPORT_afterCharList="Qt5Core.dll" + 004555C8 > 8 > 320 > 18 > 60 > 8
adrSelectedServerNAME_afterCharList="Qt5Core.dll" + 004555C8 > 8 > 320 > 18 > 60 > C

This should allow proxy bots to redirect connection to right game server.

Mahatesh
10-26-2016, 13:42
Regarding your proxy - did you manage to find a bit that resembles the 'isConnected' bit from the old client? Something that verifies that a player is currently logged in

blackd
10-29-2016, 13:52
For now, you can use this function to determine if it is connected:



Public Const CTE_NOT_CONNECTED As Integer = 0
Public Const CTE_LOGIN_CHAR_SELECTION As Integer = 1
Public Const CTE_CONNECTING As Integer = 2
Public Const CTE_GAME_CONNECTED As Integer = 3
Public Function TibiaClientConnectionStatus(ByRef pid As Long) As Long
Dim auxAdr As Long
Dim auxVal As Double
Dim pixels As Long
Dim currentCharName As String
currentCharName = ReadCurrentCharName(pid)
If Not (currentCharName = "") Then
TibiaClientConnectionStatus = CTE_GAME_CONNECTED ' 3 - Game connected
Exit Function
End If
auxAdr = ReadCurrentAddress(pid, adrSelectedItem_height, -1, False)
If (auxAdr = -1) Then
TibiaClientConnectionStatus = CTE_NOT_CONNECTED
Exit Function
End If
auxVal = QMemory_ReadDouble(pid, auxAdr)
pixels = Math.Round(auxVal)
Select Case (pixels)
Case 18
TibiaClientConnectionStatus = CTE_NOT_CONNECTED ' 0 - Not connected
Exit Function
Case 16
TibiaClientConnectionStatus = CTE_LOGIN_CHAR_SELECTION ' 1 - User at Character Selection
Exit Function
Case 100
TibiaClientConnectionStatus = CTE_CONNECTING ' 2 - Connecting... (to characer selection or to game)
Exit Function
Case 14
TibiaClientConnectionStatus = CTE_GAME_CONNECTED ' 3 - Game connected
Exit Function
Case Else
Debug.Print ("status code =" & CStr(pixels))
TibiaClientConnectionStatus = CTE_NOT_CONNECTED
Exit Function
End Select
End Function

Public Function ReadCurrentCharName(ByRef pid As Long) As String
Dim auxAdr As Long
Dim strRes As String
auxAdr = ReadCurrentAddress(pid, adrSelectedCharName, -1, True)
strRes = QMemory_ReadString(pid, auxAdr)
ReadCurrentCharName = strRes
End Function

Mahatesh
10-30-2016, 15:21
Did you ever manage to get to case 14? Being that the current character name is "" AND you are connected? Just wondering

blackd
10-31-2016, 22:11
not, really. But that is the value you would get if you check adrSelectedItem_height when you are connected while you do not open any menu.
Maybe the first mseconds after loading might reach that case, maybe not. Anyways it does not hurt to leave it there, just in case.