mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-12-12 11:12:29 +00:00
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:
parent
50e37d16bc
commit
957a4c7e2f
633 changed files with 1729 additions and 227 deletions
|
|
@ -32,6 +32,7 @@ target_include_directories(net
|
|||
target_link_libraries(net
|
||||
PRIVATE
|
||||
client
|
||||
console
|
||||
event
|
||||
PUBLIC
|
||||
bc
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ bool Login::IsReconnect() {
|
|||
return this->m_reconnect;
|
||||
}
|
||||
|
||||
bool Login::IsLoggedOn() {
|
||||
return this->m_loggedOn;
|
||||
}
|
||||
|
||||
bool Login::OnlineIdle() {
|
||||
// TODO
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue