r5sdk/r5dev/engine/client/client.cpp

375 lines
13 KiB
C++
Raw Normal View History

//===============================================================================//
//
// Purpose:
//
// $NoKeywords: $
//
//===============================================================================//
// client.cpp: implementation of the CClient class.
2022-06-16 18:04:43 +02:00
//
///////////////////////////////////////////////////////////////////////////////////
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
#include "core/stdafx.h"
#include "tier1/cvar.h"
#include "engine/server/server.h"
#include "engine/client/client.h"
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
// Purpose: gets the client from buffer by index
//---------------------------------------------------------------------------------
CClient* CClient::GetClient(int nIndex) const
{
2022-06-16 18:04:43 +02:00
return reinterpret_cast<CClient*>(
(reinterpret_cast<uintptr_t>(g_pClient) + (nIndex * sizeof(CClient))));
}
//---------------------------------------------------------------------------------
// Purpose: gets the client's team number
//---------------------------------------------------------------------------------
int64_t CClient::GetTeamNum() const
{
return m_iTeamNum;
}
//---------------------------------------------------------------------------------
// Purpose: gets the handle of this client
//---------------------------------------------------------------------------------
edict_t CClient::GetHandle(void) const
{
return m_nHandle;
}
//---------------------------------------------------------------------------------
// Purpose: gets the userID of this client
//---------------------------------------------------------------------------------
int CClient::GetUserID(void) const
{
return m_nUserID;
}
//---------------------------------------------------------------------------------
// Purpose: gets the nucleusID of this client
//---------------------------------------------------------------------------------
uint64_t CClient::GetNucleusID(void) const
{
return m_nNucleusID;
}
//---------------------------------------------------------------------------------
// Purpose: gets the signon state of this client
//---------------------------------------------------------------------------------
SIGNONSTATE CClient::GetSignonState(void) const
{
return m_nSignonState;
}
//---------------------------------------------------------------------------------
// Purpose: gets the persistence state of this client
//---------------------------------------------------------------------------------
PERSISTENCE CClient::GetPersistenceState(void) const
{
return m_nPersistenceState;
}
//---------------------------------------------------------------------------------
// Purpose: gets the net channel of this client
//---------------------------------------------------------------------------------
CNetChan* CClient::GetNetChan(void) const
{
return m_NetChannel;
}
//---------------------------------------------------------------------------------
// Purpose: gets the pointer to the server object
//---------------------------------------------------------------------------------
CServer* CClient::GetServer(void) const
{
return m_pServer;
}
//---------------------------------------------------------------------------------
// Purpose: gets the command tick
//---------------------------------------------------------------------------------
int CClient::GetCommandTick(void) const
{
return m_nCommandTick;
}
//---------------------------------------------------------------------------------
2022-06-14 21:43:32 +02:00
// Purpose: gets the name of this client (managed by server)
//---------------------------------------------------------------------------------
const char* CClient::GetServerName(void) const
{
return m_szServerName;
}
//---------------------------------------------------------------------------------
2022-06-14 21:43:32 +02:00
// Purpose: gets the name of this client (obtained from connectionless packet)
//---------------------------------------------------------------------------------
const char* CClient::GetClientName(void) const
{
return m_szClientName;
}
//---------------------------------------------------------------------------------
// Purpose: sets the handle of this client
//---------------------------------------------------------------------------------
void CClient::SetHandle(edict_t nHandle)
{
m_nHandle = nHandle;
}
//---------------------------------------------------------------------------------
// Purpose: sets the userID of this client
//---------------------------------------------------------------------------------
void CClient::SetUserID(uint32_t nUserID)
{
m_nUserID = nUserID;
}
//---------------------------------------------------------------------------------
// Purpose: sets the nucleusID of this client
//---------------------------------------------------------------------------------
void CClient::SetNucleusID(uint64_t nNucleusID)
{
m_nNucleusID = nNucleusID;
}
//---------------------------------------------------------------------------------
// Purpose: sets the signon state of this client
//---------------------------------------------------------------------------------
void CClient::SetSignonState(SIGNONSTATE nSignonState)
{
m_nSignonState = nSignonState;
}
//---------------------------------------------------------------------------------
// Purpose: sets the persistence state of this client
//---------------------------------------------------------------------------------
void CClient::SetPersistenceState(PERSISTENCE nPersistenceState)
{
m_nPersistenceState = nPersistenceState;
}
//---------------------------------------------------------------------------------
// Purpose: sets the net channel of this client
// !TODO : Remove this and rebuild INetChannel
//---------------------------------------------------------------------------------
void CClient::SetNetChan(CNetChan* pNetChan)
{
m_NetChannel = pNetChan;
}
//---------------------------------------------------------------------------------
// Purpose: checks if client is connected to server
// Output : true if connected, false otherwise
//---------------------------------------------------------------------------------
bool CClient::IsConnected(void) const
{
return m_nSignonState >= SIGNONSTATE::SIGNONSTATE_CONNECTED;
}
//---------------------------------------------------------------------------------
// Purpose: checks if client is spawned to server
// Output : true if connected, false otherwise
//---------------------------------------------------------------------------------
bool CClient::IsSpawned(void) const
{
return m_nSignonState >= SIGNONSTATE::SIGNONSTATE_NEW;
}
//---------------------------------------------------------------------------------
// Purpose: checks if client is active to server
// Output : true if connected, false otherwise
//---------------------------------------------------------------------------------
bool CClient::IsActive(void) const
{
return m_nSignonState == SIGNONSTATE::SIGNONSTATE_FULL;
}
//---------------------------------------------------------------------------------
// Purpose: checks if client's persistence data is available
// Output : true if available, false otherwise
//---------------------------------------------------------------------------------
bool CClient::IsPersistenceAvailable(void) const
{
return m_nPersistenceState >= PERSISTENCE::PERSISTENCE_AVAILABLE;
}
//---------------------------------------------------------------------------------
// Purpose: checks if client's persistence data is ready
// Output : true if ready, false otherwise
//---------------------------------------------------------------------------------
bool CClient::IsPersistenceReady(void) const
{
return m_nPersistenceState == PERSISTENCE::PERSISTENCE_READY;
}
//---------------------------------------------------------------------------------
// Purpose: checks if client is a fake client
// Output : true if connected, false otherwise
//---------------------------------------------------------------------------------
bool CClient::IsFakeClient(void) const
{
return m_bFakePlayer;
}
//---------------------------------------------------------------------------------
// Purpose: checks if this client is an actual human player
// Output : true if human, false otherwise
//---------------------------------------------------------------------------------
bool CClient::IsHumanPlayer(void) const
{
if (!IsConnected())
return false;
if (IsFakeClient())
return false;
return true;
}
2022-05-21 18:56:56 +02:00
//---------------------------------------------------------------------------------
// Purpose: throw away any residual garbage in the channel
//---------------------------------------------------------------------------------
void CClient::Clear(void)
{
2022-09-22 00:08:49 +02:00
#ifndef CLIENT_DLL
g_ServerPlayer[GetUserID()].Reset(); // Reset ServerPlayer slot.
2022-09-22 00:08:49 +02:00
#endif // !CLIENT_DLL
2022-05-21 18:56:56 +02:00
v_CClient_Clear(this);
}
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
// Purpose: throw away any residual garbage in the channel
// Input : *pClient -
//---------------------------------------------------------------------------------
void CClient::VClear(CClient* pClient)
2022-05-21 18:56:56 +02:00
{
2022-09-22 00:08:49 +02:00
#ifndef CLIENT_DLL
g_ServerPlayer[pClient->GetUserID()].Reset(); // Reset ServerPlayer slot.
2022-09-22 00:08:49 +02:00
#endif // !CLIENT_DLL
v_CClient_Clear(pClient);
2022-05-21 18:56:56 +02:00
}
//---------------------------------------------------------------------------------
// Purpose: connect new client
// Input : *szName -
// *pNetChannel -
// bFakePlayer -
// *a5 -
// *szMessage -
// nMessageSize -
// Output : true if connection was successful, false otherwise
2022-05-21 18:56:56 +02:00
//---------------------------------------------------------------------------------
bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize)
{
2022-05-21 18:56:56 +02:00
return v_CClient_Connect(this, szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize);
}
//---------------------------------------------------------------------------------
// Purpose: connect new client
// Input : *pClient -
// *szName -
// *pNetChannel -
// bFakePlayer -
// *a5 -
// *szMessage -
// nMessageSize -
// Output : true if connection was successful, false otherwise
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
2022-05-21 18:56:56 +02:00
bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize)
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
{
bool bResult = v_CClient_Connect(pClient, szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize);
2022-09-22 00:08:49 +02:00
#ifndef CLIENT_DLL
g_ServerPlayer[pClient->GetUserID()].Reset(); // Reset ServerPlayer slot.
2022-09-22 00:08:49 +02:00
#endif // !CLIENT_DLL
return bResult;
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
}
//---------------------------------------------------------------------------------
// Purpose: disconnect client
// Input : nRepLvl -
// *szReason -
// ... -
//---------------------------------------------------------------------------------
void CClient::Disconnect(const Reputation_t nRepLvl, const char* szReason, ...)
{
if (m_nSignonState != SIGNONSTATE::SIGNONSTATE_NONE)
{
char szBuf[1024];
{/////////////////////////////
va_list vArgs{};
va_start(vArgs, szReason);
vsnprintf(szBuf, sizeof(szBuf), szReason, vArgs);
szBuf[sizeof(szBuf) - 1] = '\0';
va_end(vArgs);
}/////////////////////////////
v_CClient_Disconnect(this, nRepLvl, szBuf);
}
}
bool CClient::SendNetMsg(CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice)
{
return v_CClient_SendNetMsg(this, pMsg, bLocal, bForceReliable, bVoice);
}
void* CClient::VSendSnapshot(CClient* pClient, CClientFrame* pFrame, int nTick, int nTickAck)
{
return v_CClient_SendSnapshot(pClient, pFrame, nTick, nTickAck);
}
//---------------------------------------------------------------------------------
// Purpose: process string commands (kicking anyone attempting to DOS)
// Input : *pClient - (ADJ)
// *pMsg -
// Output : false if cmd should be passed to CServerGameClients
//---------------------------------------------------------------------------------
bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg)
{
#ifndef CLIENT_DLL
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1)
CClient* pClient_Adj = pClient;
#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
/* Original function called method "CClient::ExecuteStringCommand" with an optimization
* that shifted the 'this' pointer with 8 bytes.
* Since this has been inlined with "CClient::ProcessStringCmd" as of S2, the shifting
* happens directly to anything calling this function. */
char* pShifted = reinterpret_cast<char*>(pClient) - 8;
CClient* pClient_Adj = reinterpret_cast<CClient*>(pShifted);
#endif // !GAMEDLL_S0 || !GAMEDLL_S1
int nUserID = pClient_Adj->GetUserID();
ServerPlayer_t* pSlot = &g_ServerPlayer[nUserID];
double flStartTime = Plat_FloatTime();
2022-09-22 21:20:37 +02:00
int nCmdQuotaLimit = sv_quota_stringCmdsPerSecond->GetInt();
2022-09-22 21:20:37 +02:00
if (!nCmdQuotaLimit)
return true;
if (flStartTime - pSlot->m_flStringCommandQuotaTimeStart >= 1.0)
{
pSlot->m_flStringCommandQuotaTimeStart = flStartTime;
pSlot->m_nStringCommandQuotaCount = 0;
}
++pSlot->m_nStringCommandQuotaCount;
2022-09-22 21:20:37 +02:00
if (pSlot->m_nStringCommandQuotaCount > nCmdQuotaLimit)
{
const char* pszAddress = pClient_Adj->GetNetChan()->GetAddress();
const uint64_t nNucleusID = pClient_Adj->GetNucleusID();
pClient_Adj->Disconnect(Reputation_t::REP_MARK_BAD, "#DISCONNECT_STRINGCMD_OVERFLOW");
Warning(eDLL_T::SERVER, "Removed client '%s' from slot #%i ('%llu' exceeded string command quota!)\n",
pszAddress, nUserID, nNucleusID);
return true;
}
#endif // !CLIENT_DLL
return v_CClient_ProcessStringCmd(pClient, pMsg);
}
2022-03-27 23:50:35 +02:00
///////////////////////////////////////////////////////////////////////////////
CClient* g_pClient = nullptr;