feat(glue): add realm and character handling (#7)

* fix(build): make project compilable

* feat(glue): update Character Selection screen to support switching

* fix(ui): fix CSimpleFontString::GetHeight() to use proper method

* feat(db): add static database classes from whoa-autocode

* feat(ui): use class and area IDs for Character Selection

* chore(db): update ItemRandomPropertiesRec

* feat(glue): update CCharacterSelection methods

* chore(db): uncomment DB records

* feat(glue): implement character deletion

* feat(gx): update supported text tags in GxuDetermineQuotedCode

* fix(ui): fix CSimpleFontString to use the FixedColor flag only if the string does not contain color tags

* feat(net): implement GrunLogin::LogOff

* feat(net): implement NetClient::Disconnect

* feat(login): implement trimming of realm name in LoginResponse::HandleRealmData

* feat(net): implement proper disconnection from login and realm servers

* feat(net): implement PING/PONG messages

* feat(net): add NetClient::Destroy method

* feat(net): implement ClientServices::GetRealmList (second request of Realm List)

* feat(glue): implement CGlueMgr::PollRealmList

* feat(glue): implement CGlueMgr::PollCreateCharacter

* chore(glue): add skeleton of CCharacterComponent class

* fix(build): fix build using latest features

* fix(glue): kill gotos in CGlueMgr::NetDisconnectHandler

* fix(build): include SDL3

---------

Co-authored-by: superp00t <superp00t@tutanota.com>
This commit is contained in:
VDm 2025-04-17 01:32:37 +04:00 committed by GitHub
parent 50e37d16bc
commit 957a4c7e2f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
633 changed files with 1729 additions and 227 deletions

View file

@ -32,6 +32,7 @@ target_include_directories(net
target_link_libraries(net
PRIVATE
client
console
event
PUBLIC
bc

View file

@ -1174,6 +1174,7 @@ enum NETSTATE {
NS_STATE_3 = 3,
NS_CONNECTING = 4,
NS_CONNECTED = 5,
NS_DISCONNECTING = 6
};
enum WOW_CONN_STATE {
@ -1285,5 +1286,28 @@ struct CHARACTER_INFO {
uint8_t firstLogin;
};
struct CHARACTER_CREATE_INFO {
uint8_t unk[24];
uint32_t raceID;
uint32_t sexID;
};
struct CLIENT_NETSTATS {
uint32_t bytesSent;
uint32_t messagesSent;
uint32_t sendTimestamp;
uint32_t bytesReceived;
uint32_t messagesReceived;
uint32_t receivTimestamp;
uint32_t logTimestamp;
uint32_t unk1;
uint32_t unk2;
uint32_t unk3;
uint32_t unk4;
};
typedef void (*ENUMERATE_CHARACTERS_CALLBACK)(CHARACTER_INFO&, void*);
#endif

View file

@ -3,113 +3,8 @@
#include "client/ClientServices.hpp"
#include "ui/FrameScript.hpp"
#include <storm/Error.hpp>
#include <common/DataStore.hpp>
const char* s_errorCodeTokens[] = {
"RESPONSE_SUCCESS",
"RESPONSE_FAILURE",
"RESPONSE_CANCELLED",
"RESPONSE_DISCONNECTED",
"RESPONSE_FAILED_TO_CONNECT",
"RESPONSE_CONNECTED",
"RESPONSE_VERSION_MISMATCH",
"CSTATUS_CONNECTING",
"CSTATUS_NEGOTIATING_SECURITY",
"CSTATUS_NEGOTIATION_COMPLETE",
"CSTATUS_NEGOTIATION_FAILED",
"CSTATUS_AUTHENTICATING",
"AUTH_OK",
"AUTH_FAILED",
"AUTH_REJECT",
"AUTH_BAD_SERVER_PROOF",
"AUTH_UNAVAILABLE",
"AUTH_SYSTEM_ERROR",
"AUTH_BILLING_ERROR",
"AUTH_BILLING_EXPIRED",
"AUTH_VERSION_MISMATCH",
"AUTH_UNKNOWN_ACCOUNT",
"AUTH_INCORRECT_PASSWORD",
"AUTH_SESSION_EXPIRED",
"AUTH_SERVER_SHUTTING_DOWN",
"AUTH_ALREADY_LOGGING_IN",
"AUTH_LOGIN_SERVER_NOT_FOUND",
"AUTH_WAIT_QUEUE",
"AUTH_BANNED",
"AUTH_ALREADY_ONLINE",
"AUTH_NO_TIME",
"AUTH_DB_BUSY",
"AUTH_SUSPENDED",
"AUTH_PARENTAL_CONTROL",
"AUTH_LOCKED_ENFORCED",
"REALM_LIST_IN_PROGRESS",
"REALM_LIST_SUCCESS",
"REALM_LIST_FAILED",
"REALM_LIST_INVALID",
"REALM_LIST_REALM_NOT_FOUND",
"ACCOUNT_CREATE_IN_PROGRESS",
"ACCOUNT_CREATE_SUCCESS",
"ACCOUNT_CREATE_FAILED",
"CHAR_LIST_RETRIEVING",
"CHAR_LIST_RETRIEVED",
"CHAR_LIST_FAILED",
"CHAR_CREATE_IN_PROGRESS",
"CHAR_CREATE_SUCCESS",
"CHAR_CREATE_ERROR",
"CHAR_CREATE_FAILED",
"CHAR_CREATE_NAME_IN_USE",
"CHAR_CREATE_DISABLED",
"CHAR_CREATE_PVP_TEAMS_VIOLATION",
"CHAR_CREATE_SERVER_LIMIT",
"CHAR_CREATE_ACCOUNT_LIMIT",
"CHAR_CREATE_SERVER_QUEUE",
"CHAR_CREATE_ONLY_EXISTING",
"CHAR_CREATE_EXPANSION",
"CHAR_CREATE_EXPANSION_CLASS",
"CHAR_CREATE_LEVEL_REQUIREMENT",
"CHAR_CREATE_UNIQUE_CLASS_LIMIT",
"CHAR_CREATE_CHARACTER_IN_GUILD",
"CHAR_CREATE_RESTRICTED_RACECLASS",
"CHAR_CREATE_CHARACTER_CHOOSE_RACE",
"CHAR_CREATE_CHARACTER_ARENA_LEADER",
"CHAR_CREATE_CHARACTER_DELETE_MAIL",
"CHAR_CREATE_CHARACTER_SWAP_FACTION",
"CHAR_CREATE_CHARACTER_RACE_ONLY",
"CHAR_CREATE_CHARACTER_GOLD_LIMIT",
"CHAR_CREATE_FORCE_LOGIN",
"CHAR_DELETE_IN_PROGRESS",
"CHAR_DELETE_SUCCESS",
"CHAR_DELETE_FAILED",
"CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER",
"CHAR_DELETE_FAILED_GUILD_LEADER",
"CHAR_DELETE_FAILED_ARENA_CAPTAIN",
"CHAR_LOGIN_IN_PROGRESS",
"CHAR_LOGIN_SUCCESS",
"CHAR_LOGIN_NO_WORLD",
"CHAR_LOGIN_DUPLICATE_CHARACTER",
"CHAR_LOGIN_NO_INSTANCES",
"CHAR_LOGIN_FAILED",
"CHAR_LOGIN_DISABLED",
"CHAR_LOGIN_NO_CHARACTER",
"CHAR_LOGIN_LOCKED_FOR_TRANSFER",
"CHAR_LOGIN_LOCKED_BY_BILLING",
"CHAR_LOGIN_LOCKED_BY_MOBILE_AH",
"CHAR_NAME_SUCCESS",
"CHAR_NAME_FAILURE",
"CHAR_NAME_NO_NAME",
"CHAR_NAME_TOO_SHORT",
"CHAR_NAME_TOO_LONG",
"CHAR_NAME_INVALID_CHARACTER",
"CHAR_NAME_MIXED_LANGUAGES",
"CHAR_NAME_PROFANE",
"CHAR_NAME_RESERVED",
"CHAR_NAME_INVALID_APOSTROPHE",
"CHAR_NAME_MULTIPLE_APOSTROPHES",
"CHAR_NAME_THREE_CONSECUTIVE",
"CHAR_NAME_INVALID_SPACE",
"CHAR_NAME_CONSECUTIVE_SPACES",
"CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS",
"CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END",
"CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME",
};
void ClientConnection::AccountLogin(const char* name, const char* password, int32_t region, int32_t locale) {
STORM_ASSERT(this->m_statusComplete == 1);
@ -141,6 +36,13 @@ void ClientConnection::GetCharacterList() {
}
}
void ClientConnection::EnumerateCharacters(ENUMERATE_CHARACTERS_CALLBACK fcn, void* param) {
STORM_ASSERT(fcn);
for (uint32_t i = 0; i < this->m_characterList.Count(); ++i) {
fcn(this->m_characterList[i], param);
}
}
void ClientConnection::CharacterLogin(uint64_t id) {
this->Initiate(COP_LOGIN_CHARACTER, 76, nullptr);
if (this->m_connected) {
@ -150,6 +52,19 @@ void ClientConnection::CharacterLogin(uint64_t id) {
}
}
void ClientConnection::DeleteCharacter(uint64_t guid) {
this->Initiate(COP_DELETE_CHARACTER, 70, nullptr);
if (this->m_connected) {
CDataStore msg;
msg.Put(static_cast<uint32_t>(CMSG_CHAR_DELETE));
msg.Put(guid);
msg.Finalize();
this->Send(&msg);
} else {
this->Cancel(4);
}
}
void ClientConnection::Cancel(int32_t errorCode) {
this->Complete(0, errorCode);
}
@ -185,7 +100,9 @@ void ClientConnection::Connect() {
}
int32_t ClientConnection::Disconnect() {
// TODO
this->NetClient::Disconnect();
this->m_connected = 0;
// TODO: WardenClient_Destroy();
return 0;
}
@ -220,8 +137,10 @@ int32_t ClientConnection::PollStatus(WOWCS_OPS& op, const char** msg, int32_t& r
static char altText[256];
if (this->m_statusComplete) {
auto text = errorCode >= 0 && errorCode < 104
? FrameScript_GetText(s_errorCodeTokens[errorCode], -1, GENDER_NOT_APPLICABLE)
auto errorText = ClientServices::GetErrorToken(errorCode);
auto text = errorText[0]
? FrameScript_GetText(errorText, -1, GENDER_NOT_APPLICABLE)
: nullptr;
if (!text) {

View file

@ -28,7 +28,9 @@ class ClientConnection : public RealmConnection {
void AccountLogin_Finish(int32_t authResult);
void AccountLogin_Queued();
void GetCharacterList();
void EnumerateCharacters(ENUMERATE_CHARACTERS_CALLBACK fcn, void* param);
void CharacterLogin(uint64_t id);
void DeleteCharacter(uint64_t guid);
void Cancel(int32_t errorCode);
void Cleanup();
void Connect();

View file

@ -1,5 +1,7 @@
#include "net/connection/NetClient.hpp"
#include "net/connection/WowConnection.hpp"
#include "glue/CGlueMgr.hpp"
#include "console/Console.hpp"
#include <cstdlib>
#include <cstring>
#include <new>
@ -11,7 +13,8 @@
HPROPCONTEXT s_propContext;
int32_t NetClient::s_clientCount;
CLIENT_NETSTATS NetClient::s_stats = {};
int32_t NetClient::s_clientCount = 0;
void InitializePropContext() {
if (PropGetSelectedContext() != s_propContext) {
@ -19,6 +22,11 @@ void InitializePropContext() {
}
}
NETEVENTQUEUE::~NETEVENTQUEUE() {
this->Clear();
}
void NETEVENTQUEUE::AddEvent(EVENTID eventId, void* conn, NetClient* client, const void* data, uint32_t bytes) {
this->m_critSect.Enter();
@ -98,12 +106,33 @@ void NETEVENTQUEUE::Poll() {
this->m_critSect.Leave();
}
void NETEVENTQUEUE::Clear() {
this->m_critSect.Enter();
this->m_eventQueue.Clear();
this->m_critSect.Leave();
}
void NetClient::LogStats() {
char message[128];
uint32_t time = OsGetAsyncTimeMs();
SStrPrintf(
message,
sizeof(message),
"Client net stats: %Lu bytes sent, %Lu bytes received, %Lu msec elapsed",
NetClient::s_stats.bytesSent,
NetClient::s_stats.bytesReceived,
time - s_stats.logTimestamp);
ConsoleWrite(message, DEFAULT_COLOR);
}
void NetClient::AddRef() {
SInterlockedIncrement(&this->m_refCount);
}
void NetClient::AuthChallengeHandler(WowConnection* conn, CDataStore* msg) {
auto challenge = static_cast<AuthenticationChallenge*>(SMemAlloc(sizeof(AuthenticationChallenge), __FILE__, __LINE__, 0x0));
auto challenge = NEW(AuthenticationChallenge);
uint32_t v14;
msg->Get(v14);
@ -120,7 +149,7 @@ void NetClient::AuthChallengeHandler(WowConnection* conn, CDataStore* msg) {
conn->Disconnect();
}
delete challenge;
DEL(challenge);
}
void NetClient::Connect(const char* addrStr) {
@ -144,6 +173,34 @@ void NetClient::Connect(const char* addrStr) {
this->ConnectInternal(host, port);
}
void NetClient::Disconnect() {
if (this->m_redirectConnection) {
this->m_redirectConnection->SetResponse(nullptr, false);
this->m_redirectConnection->Disconnect();
this->m_redirectConnection->Release();
}
if (this->m_netState == NS_CONNECTED) {
this->m_netState = NS_DISCONNECTING;
this->m_serverConnection->Disconnect();
} else {
this->m_serverConnection->SetResponse(nullptr, false);
this->m_serverConnection->Disconnect();
this->m_netEventQueue->Clear();
this->m_serverConnection->Release();
auto connectionMem = SMemAlloc(sizeof(WowConnection), __FILE__, __LINE__, 0x0);
if (connectionMem) {
auto connection = new (connectionMem) WowConnection(this, nullptr);
this->m_serverConnection = connection;
} else {
this->m_serverConnection = nullptr;
}
this->m_netState = NS_INITIALIZED;
}
}
int32_t NetClient::ConnectInternal(const char* host, uint16_t port) {
if (this->m_netState != NS_INITIALIZED) {
SErrDisplayAppFatal("Expected (m_netState == NS_INITIALIZED), got %d", this->m_netState);
@ -152,7 +209,12 @@ int32_t NetClient::ConnectInternal(const char* host, uint16_t port) {
this->m_netState = NS_CONNECTING;
this->m_serverConnection->Connect(host, port, -1);
// TODO
if (this->m_redirectConnection) {
this->m_redirectConnection->SetResponse(nullptr, false);
this->m_redirectConnection->Disconnect();
this->m_redirectConnection->Release();
this->m_redirectConnection = nullptr;
}
return 1;
}
@ -192,44 +254,98 @@ NETSTATE NetClient::GetState() {
return this->m_netState;
}
void NetClient::Ping() {
if (!this->m_serverConnection->m_encrypt) {
return;
}
this->m_pingLock.Enter();
this->m_pingSent = OsGetAsyncTimeMsPrecise();
CDataStore msg;
msg.Put(static_cast<uint32_t>(CMSG_PING));
msg.Put(++this->m_pingSequence);
if (this->m_netState == NS_CONNECTED) {
if (this->m_latencyEnd) {
msg.Put(this->m_latency[this->m_latencyEnd]);
} else {
msg.Put(static_cast<uint32_t>(0));
}
}
msg.Finalize();
this->m_pingLock.Leave();
this->Send(&msg);
}
int32_t NetClient::HandleCantConnect() {
// TODO
this->PushObjMgr();
STORM_ASSERT(m_netState == NS_CONNECTING);
this->m_netState = NS_INITIALIZED;
this->PopObjMgr();
return 1;
}
int32_t NetClient::ValidateMessageId(uint32_t msgId) {
// This method does nothing
return 0;
}
int32_t NetClient::HandleConnect() {
// TODO push obj mgr
this->PushObjMgr();
this->m_netState = NS_CONNECTED;
// TODO pop obj mgr
this->PopObjMgr();
return 1;
}
int32_t NetClient::HandleData(uint32_t timeReceived, void* data, int32_t size) {
// TODO push obj mgr
this->PushObjMgr();
CDataStore msg;
msg.m_data = static_cast<uint8_t*>(data);
msg.m_size = size;
msg.m_alloc = -1;
msg.m_read = 0;
NetClient::s_stats.bytesReceived += size + 2;
this->ProcessMessage(timeReceived, &msg, 0);
if (this->m_netState == NS_CONNECTED) {
CDataStore msg;
msg.m_data = static_cast<uint8_t*>(data);
msg.m_size = size;
msg.m_alloc = -1;
msg.m_read = 0;
// TODO pop obj mgr
this->ProcessMessage(timeReceived, &msg, 0);
}
this->PopObjMgr();
return 1;
}
int32_t NetClient::HandleDisconnect() {
// TODO
this->PushObjMgr();
STORM_ASSERT(this->m_netState == NS_CONNECTED || this->m_netState == NS_DISCONNECTING);
this->m_netState = NS_INITIALIZED;
ConsolePrintf("NetClient::HandleDisconnect()");
CGlueMgr::NetDisconnectHandler(this, nullptr);
this->PopObjMgr();
return 1;
}
void NetClient::HandleIdle() {
// TODO;
s_stats.unk1 = s_stats.bytesSent;
s_stats.unk2 = s_stats.bytesReceived;
s_stats.unk3 = s_stats.messagesSent;
s_stats.unk4 = s_stats.messagesReceived;
if (OsGetAsyncTimeMsPrecise() - this->m_pingSent >= 30000) {
this->Ping();
}
}
int32_t NetClient::Initialize() {
@ -261,21 +377,77 @@ int32_t NetClient::Initialize() {
return 1;
}
void NetClient::Destroy() {
if (this->m_netState == NS_UNINITIALIZED) {
return;
}
this->Disconnect();
this->m_serverConnection->SetResponse(nullptr, false);
this->m_serverConnection->Release();
this->m_serverConnection = nullptr;
memset(this->m_handlers, 0, sizeof(this->m_handlers));
memset(this->m_handlerParams, 0, sizeof(this->m_handlerParams));
if (this->m_netEventQueue) {
DEL(this->m_netEventQueue);
}
this->m_netEventQueue = nullptr;
if (--NetClient::s_clientCount == 0) {
OsSleep(1);
// TODO: WowConnection::DestroyOsNet();
}
this->m_netState = NS_UNINITIALIZED;
if (NetClient::s_clientCount == 0) {
NetClient::LogStats();
}
}
void NetClient::PollEventQueue() {
this->m_netEventQueue->Poll();
}
void NetClient::PongHandler(WowConnection* conn, CDataStore* msg) {
// TODO
if (conn != this->m_serverConnection || this->m_suspended) {
conn->Disconnect();
return;
}
this->m_pingLock.Enter();
uint32_t sequence;
msg->Get(sequence);
if (sequence == this->m_pingSequence) {
this->m_latency[this->m_latencyEnd++] = OsGetAsyncTimeMsPrecise() - this->m_pingSent;
if (this->m_latencyEnd >= 16) {
this->m_latencyEnd = 0;
}
if (this->m_latencyEnd == this->m_latencyStart) {
++this->m_latencyStart;
if (this->m_latencyStart >= 16)
this->m_latencyStart = 0;
}
} else {
ConsolePrintf("Received pong with old sequence");
}
this->m_pingLock.Leave();
}
void NetClient::ProcessMessage(uint32_t timeReceived, CDataStore* msg, int32_t a4) {
// TODO s_stats.messagesReceived++
++NetClient::s_stats.messagesReceived;
uint16_t msgId;
msg->Get(msgId);
// TODO virtual function call on NetClient
this->ValidateMessageId(msgId);
if (msgId >= NUM_MSG_TYPES || !this->m_handlers[msgId]) {
msg->Reset();
@ -324,13 +496,70 @@ void NetClient::SetLoginData(LoginData* loginData) {
memcpy(&this->m_loginData, loginData, sizeof(this->m_loginData));
}
void NetClient::DisplayNetworkStats() {
this->m_pingLock.Enter();
OsGetAsyncTimeMs();
float bandwidthIn;
float bandwidthOut;
uint32_t latency;
this->GetNetStats(bandwidthIn, bandwidthOut, latency);
this->m_pingLock.Leave();
}
void NetClient::GetNetStats(float& bandwidthIn, float& bandwidthOut, uint32_t& latency) {
this->m_pingLock.Enter();
double v5 = (double)(OsGetAsyncTimeMs() - this->m_connectedTimestamp) * 0.001;
bandwidthIn = (double)this->m_bytesReceived * 0.0009765625 / v5;
bandwidthOut = (double)this->m_bytesSent * 0.0009765625 / v5;
uint32_t latencyStart = this->m_latencyStart;
uint32_t latencyEnd = this->m_latencyEnd;
uint32_t v6 = 0;
uint32_t v9 = 0;
while (latencyStart != latencyEnd) {
if (latencyStart >= 16) {
latencyStart = 0;
if (!latencyEnd)
break;
}
v9 += this->m_latency[latencyStart];
++v6;
++latencyStart;
} ;
if (!v6) {
latency = 0;
} else {
latency = v9 / v6;
}
this->m_pingLock.Leave();
}
void NetClient::PushObjMgr() {
// TODO
}
void NetClient::PopObjMgr() {
// TODO
}
void NetClient::SetMessageHandler(NETMESSAGE msgId, MESSAGE_HANDLER handler, void* param) {
this->m_handlers[msgId] = handler;
this->m_handlerParams[msgId] = param;
}
void NetClient::WCCantConnect(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr) {
// TODO
if (conn == this->m_redirectConnection) {
// TODO
} else if (conn == this->m_serverConnection) {
this->m_netEventQueue->AddEvent(EVENT_ID_NET_CANTCONNECT, conn, this, nullptr, 0);
}
}
void NetClient::WCConnected(WowConnection* conn, WowConnection* inbound, uint32_t timeStamp, const NETCONNADDR* addr) {
@ -353,7 +582,10 @@ void NetClient::WCConnected(WowConnection* conn, WowConnection* inbound, uint32_
}
void NetClient::WCDisconnected(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr) {
// TODO
this->DisplayNetworkStats();
if (this->m_netEventQueue) {
this->m_netEventQueue->AddEvent(EVENT_ID_NET_DISCONNECT, conn, this, nullptr, 0);
}
}
void NetClient::WCMessageReady(WowConnection* conn, uint32_t timeStamp, CDataStore* msg) {

View file

@ -41,12 +41,16 @@ class NETEVENTQUEUE {
NETEVENTQUEUE(NetClient* client)
: m_client(client)
{};
~NETEVENTQUEUE();
void AddEvent(EVENTID eventId, void* conn, NetClient* client, const void* data, uint32_t bytes);
void Poll();
void Clear();
};
class NetClient : public WowConnectionResponse {
public:
static void LogStats();
// Virtual member functions
virtual void WCMessageReady(WowConnection* conn, uint32_t timeStamp, CDataStore* msg);
virtual void WCConnected(WowConnection* conn, WowConnection* inbound, uint32_t timeStamp, const NETCONNADDR* addr);
@ -57,19 +61,23 @@ class NetClient : public WowConnectionResponse {
virtual int32_t HandleConnect();
virtual int32_t HandleDisconnect();
virtual int32_t HandleCantConnect();
virtual int32_t ValidateMessageId(uint32_t msgId);
// Member functions
void AddRef();
void AuthChallengeHandler(WowConnection* conn, CDataStore* msg);
void Connect(const char* addrStr);
void Disconnect();
int32_t ConnectInternal(const char* host, uint16_t port);
void DelRef();
void EnableEncryption(WowConnection* conn, uint8_t* seed, uint8_t seedLen);
bool GetDelete();
const LoginData& GetLoginData();
NETSTATE GetState();
void Ping();
void HandleIdle();
int32_t Initialize();
void Destroy();
void PollEventQueue();
void PongHandler(WowConnection* conn, CDataStore* msg);
void ProcessMessage(uint32_t timeReceived, CDataStore* msg, int32_t a4);
@ -77,9 +85,14 @@ class NetClient : public WowConnectionResponse {
void SetDelete();
void SetLoginData(LoginData* loginData);
void SetMessageHandler(NETMESSAGE msgId, MESSAGE_HANDLER handler, void* param);
void DisplayNetworkStats();
void GetNetStats(float& bandwidthIn, float& bandwidthOut, uint32_t& latency);
void PushObjMgr();
void PopObjMgr();
private:
// Static variables
static CLIENT_NETSTATS s_stats;
static int32_t s_clientCount;
// Member variables

View file

@ -1,5 +1,6 @@
#include "net/connection/RealmConnection.hpp"
#include "net/connection/RealmResponse.hpp"
#include "net/connection/ClientConnection.hpp"
#include "net/Types.hpp"
#include <common/DataStore.hpp>
#include <common/SHA1.hpp>
@ -29,7 +30,7 @@ int32_t RealmConnection::MessageHandler(void* param, NETMESSAGE msgId, uint32_t
}
case SMSG_DELETE_CHAR: {
// TODO
result = connection->HandleCharacterDelete(msgId, time, msg);
break;
}
@ -271,6 +272,13 @@ int32_t RealmConnection::HandleCharEnum(uint32_t msgId, uint32_t time, CDataStor
return 1;
}
int32_t RealmConnection::HandleCharacterDelete(uint32_t msgId, uint32_t time, CDataStore* msg) {
uint8_t result;
msg->Get(result);
static_cast<ClientConnection*>(this)->Complete(1, result);
return 1;
}
void RealmConnection::SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4) {
// TODO
}

View file

@ -41,6 +41,7 @@ class RealmConnection : public NetClient {
RealmConnection(RealmResponse* realmResponse);
int32_t HandleAuthResponse(uint32_t msgId, uint32_t time, CDataStore* msg);
int32_t HandleCharEnum(uint32_t msgId, uint32_t time, CDataStore* msg);
int32_t HandleCharacterDelete(uint32_t msgId, uint32_t time, CDataStore* msg);
void SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4);
void RequestCharacterEnum();
void RequestCharacterLogin(uint64_t id);

View file

@ -341,8 +341,7 @@ void WowConnection::DoDisconnect() {
this->m_lock.Leave();
if (this->m_response && this->m_sock >= 0) {
// TODO
// this->m_response->Vfunc4(this, OsGetAsyncTimeMsPrecise());
this->m_response->WCDisconnected(this, OsGetAsyncTimeMsPrecise(), &this->m_peer);
}
this->m_lock.Enter();
@ -670,6 +669,27 @@ void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) {
this->m_type = WOWC_TYPE_MESSAGES;
}
void WowConnection::SetResponse(WowConnectionResponse* response, bool a3) {
while (1) {
this->m_responseLock.Enter();
if (!this->m_responseRef || this->m_responseRefThread == SGetCurrentThreadId())
break;
if (a3) {
// this->off_53 = response;
this->m_responseLock.Leave();
return;
}
this->m_responseLock.Leave();
OsSleep(50u);
}
this->m_response = response;
// this->off_53 = nullptr;
this->m_responseLock.Leave();
}
WowConnection::SENDNODE* WowConnection::NewSendNode(void* data, int32_t size, bool raw) {
// TODO counters
@ -694,8 +714,7 @@ void WowConnection::Release() {
if (WowConnection::s_network) {
WowConnection::s_network->Delete(this);
} else {
// TODO SMemFree
delete this;
DEL(this);
}
}
}

View file

@ -99,6 +99,7 @@ class WowConnection {
void FreeSendNode(SENDNODE* sn);
WOW_CONN_STATE GetState();
void Init(WowConnectionResponse* response, void (*func)(void));
void SetResponse(WowConnectionResponse* response, bool a3);
SENDNODE* NewSendNode(void* data, int32_t size, bool raw);
void Release();
void ReleaseResponseRef();

View file

@ -34,7 +34,7 @@ void WowConnectionNet::Delete(WowConnection* connection) {
this->m_connectionsLock.Enter();
if (connection->m_refCount == 0) {
delete connection;
DEL(connection);
}
this->m_connectionsLock.Leave();

View file

@ -20,6 +20,7 @@ class Grunt::ClientResponse {
virtual void RealmListResult(CDataStore* msg) = 0;
virtual LOGIN_STATE NextSecurityState(LOGIN_STATE state) = 0;
virtual int32_t GetServerId() = 0;
virtual void Reconnect() = 0;
virtual void GetRealmList() = 0;
virtual void Logon(const char* a2, const char* a3) = 0;
virtual void ProveVersion(const uint8_t* versionChecksum) = 0;

View file

@ -88,6 +88,10 @@ int32_t GruntLogin::GetServerId() {
return 0;
}
void GruntLogin::Reconnect() {
// TODO
}
void GruntLogin::GetVersionProof(const uint8_t* versionChallenge) {
if (this->IsReconnect()) {
// TODO
@ -113,7 +117,9 @@ void GruntLogin::Init(LoginResponse* loginResponse) {
}
void GruntLogin::Logoff() {
// TODO
if (this->m_loggedOn) {
this->m_clientLink->Disconnect();
}
}
void GruntLogin::Logon(const char* a2, const char* a3) {

View file

@ -22,6 +22,7 @@ class GruntLogin : public Login {
virtual void LogonResult(Grunt::Result result, const uint8_t* sessionKey, uint32_t sessionKeyLen, uint16_t flags);
virtual LOGIN_STATE NextSecurityState(LOGIN_STATE state);
virtual int32_t GetServerId();
virtual void Reconnect();
virtual void GetRealmList();
virtual void Logon(const char* a2, const char* a3);
virtual void ProveVersion(const uint8_t* versionChecksum);

View file

@ -13,6 +13,10 @@ bool Login::IsReconnect() {
return this->m_reconnect;
}
bool Login::IsLoggedOn() {
return this->m_loggedOn;
}
bool Login::OnlineIdle() {
// TODO

View file

@ -22,6 +22,7 @@ class Login : public Grunt::ClientResponse {
virtual bool OnlineIdle();
virtual void RealmListResult(CDataStore* msg);
virtual bool IsReconnect();
virtual bool IsLoggedOn();
// Member functions
void SetLogonCreds(const char* accountName, const char* password);

View file

@ -72,7 +72,62 @@ void LoginResponse::HandleRealmData(uint32_t a2, CDataStore* msg) {
realm.flags |= 0x80;
}
// TODO name manipulation
if (realm.name[0] == '\0') {
continue;
}
int32_t j = 0;
while (realm.name[j]) {
switch (realm.name[j]) {
case '"':
case '*':
case '/':
case ':':
case '<':
case '>':
case '?':
case '\\':
case '|': {
realm.name[j] = ' ';
break;
}
default: {
break;
}
}
++j;
}
while (j > 0) {
bool stop = false;
switch (realm.name[j - 1]) {
case ' ':
case '"':
case '*':
case '.':
case '/':
case ':':
case '<':
case '>':
case '?':
case '\\':
case '|': {
--j;
break;
}
default: {
stop = true;
break;
}
}
if (stop) {
break;
}
}
realm.name[j] = '\0';
}
msg->Get(reinterpret_cast<uint16_t&>(this->uint10));