• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Identifying OTClient vs Tibia vanilla client on login?

jlnunez89

a.k.a BurnMc
Premium User
Joined
Jul 5, 2007
Messages
177
Solutions
1
Reaction score
70
Location
Seattle, WA
Heyo, does anyone know of an easy way of categorizing the agent (i.e. the client) into OTClient / Vanilla on player login?

I've observed, at least for client 7.72 that there are 92 trailing bytes [0] after the password on a a Player login in packet.
I've went through some distro sources but none seem to parse or even read these bytes, which for OTCv8 contain a string [1], but for the vanilla client seem to be random.

Particularly interested for version 7.72, but if there is a general solution it'd be best, and also if this behavior is consistent in other OTC and vanilla versions? (I've been absent for a while and lost track of changes through years).

Does anyone recall what these bytes contain in the vanilla client?

Thanks!

[0]:
1593803028575.png

[1]:
1593803194913.png
 
Solution
Neat, but I guess the OTCv8 I recently cloned doesn't send it as those values and it ends up being CLIENTOS_WINDOWS = 2, , which answers my question of is it consistent... that sucks :)

Anyways, thanks for the answer!
 
Anyways, thanks for the answer!
No problem! Also, I found my old code for that additional hardware information if it's helpful in anyway to you, or anyone else:
C++:
uint8_t localeId = msg.getByte();
char localeNameBuffer[3];
for (int i = 0; i < 3; ++i) {
    localeNameBuffer[i] = static_cast<char>(msg.getByte());
}
std::string localeName = localeNameBuffer;
uint16_t ramMb = msg.get<uint16_t>();
msg.skipBytes(6); // unknown
char cpuNameBuffer[9];
for (int i = 0; i < 9; ++i) {
    cpuNameBuffer[i] = static_cast<char>(msg.getByte());
}
std::string cpuName = cpuNameBuffer;
msg.skipBytes(2); // unknown
uint16_t cpuMhz1 = msg.get<uint16_t>();
uint16_t cpuMhz2 = msg.get<uint16_t>();
msg.skipBytes(4); // unknown
char gpuNameBuffer[9];
for (int i = 0; i < 9; ++i) {
    gpuNameBuffer[i] = static_cast<char>(msg.getByte());
}
std::string gpuName = gpuNameBuffer;
uint16_t vRamMb = msg.get<uint16_t>();
uint16_t screenResolutionHorizontal = msg.get<uint16_t>();
uint16_t screenResolutionVertical = msg.get<uint16_t>();
uint8_t screenRefreshRate = msg.getByte();
I believe, if I'm remembering correctly, any bytes following this information was just padding bytes from the RSA-encryption routine.
 
That's awesome!
Do you happen to know if all vanilla clients behave this way? (sending HW info)

OTCv8 only sends that OTCv8ð string and the rest are padding zeros with an also seemingly random byte at the end. I was thinking of doing some dirty solution where I'd just sum the 92 bytes and make best guess assumptions using a threshold or a conversion to string which contains OTCv" since I only care about the pinging/heartbeat system which debugs out on vanilla 7.72 and wanted to support both (and in the future other client versions out of the box).
 
Back
Top