diff --git a/lib/common b/lib/common index 1113e84..156ccfd 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 1113e846dad906864e7e4e9e5275334f6ca3df0e +Subproject commit 156ccfdb7da35ab786530cdd956e3881b50983f7 diff --git a/src/client/ClientServices.cpp b/src/client/ClientServices.cpp index 736b0b9..a413066 100644 --- a/src/client/ClientServices.cpp +++ b/src/client/ClientServices.cpp @@ -93,6 +93,14 @@ void ClientServices::SetAccountName(const char* accountName) { SStrCopy(ClientServices::s_accountName, accountName, sizeof(ClientServices::s_accountName)); } +int32_t ClientServices::GetLoginServerType() { + if (!ClientServices::LoginConnection()) { + return 0; + } + + return ClientServices::LoginConnection()->GetLoginServerType(); +} + void ClientServices::LoginServerStatus(LOGIN_STATE state, LOGIN_RESULT result, const char* addrStr, const char* stateStr, const char* resultStr, uint8_t flags) { CGlueMgr::SetLoginStateAndResult(state, result, addrStr, stateStr, resultStr, flags); @@ -119,3 +127,7 @@ void ClientServices::LoginServerStatus(LOGIN_STATE state, LOGIN_RESULT result, c // TODO CVar::DeleteAccountCVars(); } } + +void ClientServices::RealmEnumCallback(uint32_t a2) { + // TODO +} diff --git a/src/client/ClientServices.hpp b/src/client/ClientServices.hpp index 4216dc4..04eb202 100644 --- a/src/client/ClientServices.hpp +++ b/src/client/ClientServices.hpp @@ -26,7 +26,9 @@ class ClientServices : public LoginResponse { static void SetAccountName(const char* accountName); // Virtual member functions + virtual int32_t GetLoginServerType(); virtual void LoginServerStatus(LOGIN_STATE state, LOGIN_RESULT result, const char* addrStr, const char* stateStr, const char* resultStr, uint8_t flags); + virtual void RealmEnumCallback(uint32_t a2); }; #endif diff --git a/src/net/Types.hpp b/src/net/Types.hpp index 94b2a6a..9619e0a 100644 --- a/src/net/Types.hpp +++ b/src/net/Types.hpp @@ -1225,4 +1225,24 @@ struct NETCONNADDR { NETADDR selfAddr; }; +struct REALM_INFO { + uint32_t id; + uint8_t type; + uint8_t flags; + char name[256]; + char address[32]; + float population; + uint8_t numChars; + uint8_t category; + uint32_t uint130; + uint32_t uint134; + uint32_t sort; + uint32_t uint13C; + uint8_t locked; + uint8_t majorVersion; + uint8_t minorVersion; + uint8_t patchVersion; + uint16_t revision; +}; + #endif diff --git a/src/net/grunt/ClientLink.cpp b/src/net/grunt/ClientLink.cpp index ff856c2..a0182dc 100644 --- a/src/net/grunt/ClientLink.cpp +++ b/src/net/grunt/ClientLink.cpp @@ -282,8 +282,86 @@ int32_t Grunt::ClientLink::CmdAuthReconnectProof(CDataStore& msg) { } int32_t Grunt::ClientLink::CmdRealmList(CDataStore& msg) { - // TODO - return 0; + if (msg.m_read > msg.m_size || msg.m_size - msg.m_read < 2) { + return 0; + } + + uint16_t size; + msg.Get(size); + + if (msg.m_read > msg.m_size || msg.m_size - msg.m_read < size) { + return 0; + } + + uint32_t startData = msg.m_read; + + uint32_t padding; + msg.Get(padding); + + uint32_t startList = msg.m_read; + + uint16_t count; + msg.Get(count); + + for (uint32_t i = 0; i < count && msg.m_read < msg.m_size; i++) { + uint8_t realmType; + msg.Get(realmType); + + uint8_t locked; + msg.Get(locked); + + uint8_t realmFlags; + msg.Get(realmFlags); + + char realmName[256]; + msg.GetString(realmName, sizeof(realmName)); + + char realmAddress[256]; + msg.GetString(realmAddress, sizeof(realmAddress)); + + float population; + msg.Get(population); + + uint8_t numChars; + msg.Get(numChars); + + uint8_t realmCategory; + msg.Get(realmCategory); + + uint8_t sort; + msg.Get(sort); + + // TODO SPECIFY_BUILD + if (realmFlags & 0x4) { + uint8_t major; + msg.Get(major); + + uint8_t minor; + msg.Get(minor); + + uint8_t patch; + msg.Get(patch); + + uint16_t revision; + msg.Get(revision); + } + } + + uint16_t padding2; + msg.Get(padding2); + + if (msg.m_read <= msg.m_size && msg.m_read - startData == size) { + uint32_t endData = msg.m_read; + msg.m_read = startList; + + this->m_clientResponse->RealmListResult(&msg); + + msg.m_read = endData; + + return 2; + } + + return 1; } int32_t Grunt::ClientLink::CmdXferData(CDataStore& msg) { diff --git a/src/net/grunt/ClientResponse.hpp b/src/net/grunt/ClientResponse.hpp index 4e483e0..d5e604a 100644 --- a/src/net/grunt/ClientResponse.hpp +++ b/src/net/grunt/ClientResponse.hpp @@ -4,6 +4,7 @@ #include "net/grunt/Grunt.hpp" #include "net/Types.hpp" +class CDataStore; class LoginResponse; class Grunt::ClientResponse { @@ -16,6 +17,7 @@ class Grunt::ClientResponse { virtual void SetMatrixInfo(bool enabled, uint8_t a3, uint8_t a4, uint8_t a5, uint8_t a6, bool a7, uint8_t a8, uint64_t a9, const uint8_t* a10, uint32_t a11) = 0; virtual void SetTokenInfo(bool enabled, uint8_t required) = 0; virtual void LogonResult(Result result, const uint8_t* sessionKey, uint32_t sessionKeyLen, uint16_t flags) = 0; + virtual void RealmListResult(CDataStore* msg) = 0; virtual LOGIN_STATE NextSecurityState(LOGIN_STATE state) = 0; virtual int32_t GetServerId() = 0; virtual void GetRealmList() = 0; diff --git a/src/net/login/Login.cpp b/src/net/login/Login.cpp index 49b5197..1f3bfe2 100644 --- a/src/net/login/Login.cpp +++ b/src/net/login/Login.cpp @@ -1,5 +1,7 @@ #include "net/login/Login.hpp" +#include "net/login/LoginResponse.hpp" #include +#include #include #include @@ -17,6 +19,14 @@ bool Login::OnlineIdle() { return true; } +void Login::RealmListResult(CDataStore* msg) { + if (!msg || !msg->IsFinal()) { + this->m_loginResponse->HandleRealmData(4, nullptr); + } else { + this->m_loginResponse->HandleRealmData(0, msg); + } +} + void Login::SetLogonCreds(const char* accountName, const char* password) { SStrCopy(this->m_accountName, accountName, 1280); diff --git a/src/net/login/Login.hpp b/src/net/login/Login.hpp index c4f67e2..f5f9228 100644 --- a/src/net/login/Login.hpp +++ b/src/net/login/Login.hpp @@ -3,6 +3,7 @@ #include "net/grunt/ClientResponse.hpp" +class CDataStore; class LoginResponse; class Login : public Grunt::ClientResponse { @@ -19,6 +20,7 @@ class Login : public Grunt::ClientResponse { // Virtual member functions virtual ~Login(); virtual bool OnlineIdle(); + virtual void RealmListResult(CDataStore* msg); virtual bool IsReconnect(); // Member functions diff --git a/src/net/login/LoginResponse.cpp b/src/net/login/LoginResponse.cpp index fd497cc..cc6251b 100644 --- a/src/net/login/LoginResponse.cpp +++ b/src/net/login/LoginResponse.cpp @@ -1,7 +1,92 @@ #include "net/login/LoginResponse.hpp" #include "net/grunt/Grunt.hpp" +#include #include +void LoginResponse::HandleRealmData(uint32_t a2, CDataStore* msg) { + this->m_realmList.Clear(); + + if (a2 || !msg) { + this->RealmEnumCallback(a2); + return; + } + + uint16_t count; + msg->Get(count); + + this->m_realmList.SetCount(count); + + for (uint32_t i = 0; i < count; i++) { + auto& realm = this->m_realmList[i]; + + realm.id = i; + + msg->Get(realm.type); + msg->Get(realm.locked); + msg->Get(realm.flags); + msg->GetString(realm.name, sizeof(realm.name)); + msg->GetString(realm.address, sizeof(realm.address)); + msg->Get(realm.population); + msg->Get(realm.numChars); + msg->Get(realm.category); + + if (this->GetLoginServerType() == 1) { + msg->Get(realm.uint130); + msg->Get(realm.uint134); + msg->Get(realm.sort); + msg->Get(realm.uint13C); + } else { + uint8_t sort; + msg->Get(sort); + realm.sort = sort; + + realm.uint130 = 0; + realm.uint134 = 0; + realm.uint13C = 0; + } + + if (realm.flags & 0x4) { + msg->Get(realm.majorVersion); + msg->Get(realm.minorVersion); + msg->Get(realm.patchVersion); + msg->Get(realm.revision); + } else { + realm.majorVersion = 0; + realm.minorVersion = 0; + realm.patchVersion = 0; + realm.revision = 0; + } + + if (msg->m_read > msg->m_size) { + break; + } + + if (realm.population == 600.0f) { + realm.population = 0.0f; + realm.flags |= 0x20; + } else if (realm.population == 200.0f) { + realm.population = 0.001f; + realm.flags |= 0x40; + } else if (realm.population == 400.f) { + realm.population = 8.0f; + realm.flags |= 0x80; + } + + // TODO name manipulation + } + + msg->Get(reinterpret_cast(this->uint10)); + + // Overrun or underrun + if (msg->m_read > msg->m_size || !msg->IsRead()) { + this->m_realmList.Clear(); + this->RealmEnumCallback(4); + } + + // Success + this->RealmEnumCallback(a2); +} + void LoginResponse::UpdateLoginStatus(LOGIN_STATE state, LOGIN_RESULT result, const char* addrStr, uint16_t flags) { this->m_loginState = state; this->m_loginResult = result; diff --git a/src/net/login/LoginResponse.hpp b/src/net/login/LoginResponse.hpp index 4617129..ea2417e 100644 --- a/src/net/login/LoginResponse.hpp +++ b/src/net/login/LoginResponse.hpp @@ -2,17 +2,25 @@ #define NET_LOGIN_LOGIN_RESPONSE_HPP #include "net/Types.hpp" +#include + +class CDataStore; class LoginResponse { public: // Member variables + TSFixedArray m_realmList; + uint32_t uint10; LOGIN_STATE m_loginState; LOGIN_RESULT m_loginResult; // Virtual member functions + virtual int32_t GetLoginServerType() = 0; virtual void LoginServerStatus(LOGIN_STATE state, LOGIN_RESULT result, const char* addrStr, const char* stateStr, const char* resultStr, uint8_t flags) = 0; + virtual void RealmEnumCallback(uint32_t a2) = 0; // Member functions + void HandleRealmData(uint32_t a2, CDataStore* msg); void UpdateLoginStatus(LOGIN_STATE state, LOGIN_RESULT result, const char* addrStr, uint16_t flags); };