From 4bef9fc6cf3ac019264e152a81317e0389129789 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:25:11 +0200 Subject: [PATCH 01/24] Light script cleanup - Rename 'checksum' to 'digest'. - Sort the data in the correct order to reduce load on the client (client sorts it to the same order). --- r5dev/resource/script/bld_man.py | 40 +++++++++++++++----------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/r5dev/resource/script/bld_man.py b/r5dev/resource/script/bld_man.py index 9a5cabf5..8beef1a8 100644 --- a/r5dev/resource/script/bld_man.py +++ b/r5dev/resource/script/bld_man.py @@ -5,24 +5,24 @@ import json import hashlib #------------------------------------------------------------------------------ -# Compute the SHA-256 checksum of a file +# Compute the SHA-256 digest of a file #------------------------------------------------------------------------------ -def ComputeChecksum(filePath, blockSize=65536): +def ComputeDigest(filePath, blockSize=65536): sha256 = hashlib.sha256() with open(filePath, "rb") as file: for block in iter(lambda: file.read(blockSize), b""): sha256.update(block) - checksum = sha256.hexdigest() - print(f"*** computed checksum for '{filePath}': {checksum}") + digest = sha256.hexdigest() + print(f"*** computed digest for '{filePath}': {digest}") - return checksum + return digest #------------------------------------------------------------------------------ -# Compute checksums for all files in a directory +# Compute digests for all files in a directory #------------------------------------------------------------------------------ -def RecursiveComputeChecksum(directoryPath, settings): - checksums = {} +def RecursiveComputeDigest(directoryPath, settings): + digests = {} scriptPath = os.path.abspath(__file__) for root, _, files in os.walk(directoryPath): @@ -35,9 +35,9 @@ def RecursiveComputeChecksum(directoryPath, settings): if os.path.abspath(filePath) == scriptPath: continue - checksum = ComputeChecksum(filePath) - checksums[normalizedPath] = { - "checksum": checksum, + digest = ComputeDigest(filePath) + digests[normalizedPath] = { + "digest": digest, "restart": False } @@ -45,11 +45,10 @@ def RecursiveComputeChecksum(directoryPath, settings): if settings and "restart" in settings: restart_files = settings["restart"] for file in restart_files: - if file in checksums: - checksums[file]["restart"] = True - - return checksums + if file in digests: + digests[file]["restart"] = True + return digests #------------------------------------------------------------------------------ # Gets the settings for this depot @@ -69,9 +68,8 @@ def GetDepotSettings(depotName): return json.load(f) - #------------------------------------------------------------------------------ -# Save the checksums to a manifest file +# build the manifest file #------------------------------------------------------------------------------ def CreateManifest(version, currentDirectory, outManifestFile): depotList = [name for name in os.listdir(currentDirectory) if os.path.isdir(os.path.join(currentDirectory, name))] @@ -99,16 +97,16 @@ def CreateManifest(version, currentDirectory, outManifestFile): print(f"*** processing depot '{depot}'...") - checksum = ComputeChecksum(zipFilePath) + digest = ComputeDigest(zipFilePath) size = os.path.getsize(zipFilePath) depotData = { + "assets": RecursiveComputeDigest(os.path.join(currentDirectory, depot), settings), + "digest": digest, "name": fileName, - "size": size, - "checksum": checksum, "optional": False, + "size": size, "vendor": settings["vendor"], - "assets": RecursiveComputeChecksum(os.path.join(currentDirectory, depot), settings) } manifest["depot"][i] = depotData From 6eb3388aee2cbb997def4dffcdb670c23cc3f217 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 10:40:50 +0200 Subject: [PATCH 02/24] Default to nullptr If null, it uses the statically created breakset. --- r5dev/public/tier1/cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/r5dev/public/tier1/cmd.h b/r5dev/public/tier1/cmd.h index fd82e159..cd35ff6c 100644 --- a/r5dev/public/tier1/cmd.h +++ b/r5dev/public/tier1/cmd.h @@ -77,7 +77,7 @@ private: public: CCommand(); CCommand(int nArgC, const char** ppArgV, cmd_source_t source); - bool Tokenize(const char* pCommand, cmd_source_t source, characterset_t* pBreakSet); + bool Tokenize(const char* pCommand, cmd_source_t source, characterset_t* pBreakSet = nullptr); int64_t ArgC(void) const; const char** ArgV(void) const; From ddfe027677991f268aaad213801b4399b204e776 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 10:48:22 +0200 Subject: [PATCH 03/24] Pass by reference CConnectedNetConsoleData was allocated and deallocated manually, but std::vector is able to do it on its own. The vector type has been swapped out with CUtlVector as this removed the need of having to cast size types to a 32bit int to make it more compatible with the other sdk/engine types without throwing compiler warnings. --- r5dev/engine/client/cl_rcon.cpp | 2 +- r5dev/engine/server/sv_rcon.cpp | 68 ++++++++++++++--------------- r5dev/engine/server/sv_rcon.h | 4 +- r5dev/engine/shared/base_rcon.cpp | 53 ++++++++++------------ r5dev/engine/shared/base_rcon.h | 4 +- r5dev/engine/shared/shared_rcon.cpp | 4 +- r5dev/netconsole/netconsole.cpp | 2 +- r5dev/public/tier2/socketcreator.h | 16 +++---- r5dev/tier2/socketcreator.cpp | 55 ++++++++++++----------- 9 files changed, 103 insertions(+), 105 deletions(-) diff --git a/r5dev/engine/client/cl_rcon.cpp b/r5dev/engine/client/cl_rcon.cpp index a6a5e93a..a0120ffb 100644 --- a/r5dev/engine/client/cl_rcon.cpp +++ b/r5dev/engine/client/cl_rcon.cpp @@ -59,7 +59,7 @@ void CRConClient::RunFrame(void) if (pData) { - Recv(pData); + Recv(*pData); } } } diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index 46a2ea0f..2ca7736e 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -97,8 +97,8 @@ void CRConServer::Think(void) const netadr_t& netAdr = m_Socket.GetAcceptedSocketAddress(m_nConnIndex); if (!m_WhiteListAddress.CompareAdr(netAdr)) { - const CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); - if (!pData->m_bAuthorized) + const CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); + if (!pData.m_bAuthorized) { Disconnect("redundant"); } @@ -169,11 +169,11 @@ void CRConServer::RunFrame(void) const int nCount = m_Socket.GetAcceptedSocketCount(); for (m_nConnIndex = nCount - 1; m_nConnIndex >= 0; m_nConnIndex--) { - CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); + CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); if (CheckForBan(pData)) { - SendEncode(pData->m_hSocket, s_BannedMessage, "", + SendEncode(pData.m_hSocket, s_BannedMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, int(eDLL_T::NETCON)); Disconnect("banned"); @@ -204,11 +204,11 @@ bool CRConServer::SendToAll(const char* pMsgBuf, const int nMsgLen) const const int nCount = m_Socket.GetAcceptedSocketCount(); for (int i = nCount - 1; i >= 0; i--) { - CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(i); + const CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(i); - if (pData->m_bAuthorized) + if (pData.m_bAuthorized) { - int ret = ::send(pData->m_hSocket, sendbuf.str().data(), + int ret = ::send(pData.m_hSocket, sendbuf.str().data(), int(sendbuf.str().size()), MSG_NOSIGNAL); if (ret == SOCKET_ERROR) @@ -317,9 +317,9 @@ bool CRConServer::Serialize(vector& vecBuf, const char* pResponseMsg, cons // Input : &request - // *pData - //----------------------------------------------------------------------------- -void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetConsoleData* pData) +void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetConsoleData& pData) { - if (pData->m_bAuthorized) + if (pData.m_bAuthorized) { return; } @@ -327,14 +327,14 @@ void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetCon { if (Comparator(request.requestmsg())) { - pData->m_bAuthorized = true; + pData.m_bAuthorized = true; if (++m_nAuthConnections >= sv_rcon_maxconnections->GetInt()) { m_Socket.CloseListenSocket(); CloseNonAuthConnection(); } - SendEncode(pData->m_hSocket, s_AuthMessage, sv_rcon_sendlogs->GetString(), + SendEncode(pData.m_hSocket, s_AuthMessage, sv_rcon_sendlogs->GetString(), sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast(eDLL_T::NETCON)); } else // Bad password. @@ -345,12 +345,12 @@ void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetCon DevMsg(eDLL_T::SERVER, "Bad RCON password attempt from '%s'\n", netAdr.ToString()); } - SendEncode(pData->m_hSocket, s_WrongPwMessage, "", + SendEncode(pData.m_hSocket, s_WrongPwMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast(eDLL_T::NETCON)); - pData->m_bAuthorized = false; - pData->m_bValidated = false; - pData->m_nFailedAttempts++; + pData.m_bAuthorized = false; + pData.m_bValidated = false; + pData.m_nFailedAttempts++; } } } @@ -385,7 +385,7 @@ bool CRConServer::Comparator(const string& svPassword) const //----------------------------------------------------------------------------- bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) { - CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); + CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); cl_rcon::request request; if (!Decode(&request, pMsgBuf, nMsgLen)) @@ -394,15 +394,15 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) return false; } - if (!pData->m_bAuthorized && + if (!pData.m_bAuthorized && request.requesttype() != cl_rcon::request_t::SERVERDATA_REQUEST_AUTH) { // Notify netconsole that authentication is required. - SendEncode(pData->m_hSocket, s_NoAuthMessage, "", + SendEncode(pData.m_hSocket, s_NoAuthMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast(eDLL_T::NETCON)); - pData->m_bValidated = false; - pData->m_nIgnoredMessage++; + pData.m_bValidated = false; + pData.m_nIgnoredMessage++; return true; } switch (request.requesttype()) @@ -414,7 +414,7 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) } case cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND: { - if (pData->m_bAuthorized) // Only execute if auth was successful. + if (pData.m_bAuthorized) // Only execute if auth was successful. { Execute(request, false); } @@ -422,7 +422,7 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) } case cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE: { - if (pData->m_bAuthorized) + if (pData.m_bAuthorized) { Execute(request, true); } @@ -430,7 +430,7 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) } case cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG: { - if (pData->m_bAuthorized) + if (pData.m_bAuthorized) { sv_rcon_sendlogs->SetValue(request.requestval().c_str()); } @@ -470,9 +470,9 @@ void CRConServer::Execute(const cl_rcon::request& request, const bool bConVar) c // Purpose: checks for amount of failed attempts and bans netconsole accordingly // Input : *pData - //----------------------------------------------------------------------------- -bool CRConServer::CheckForBan(CConnectedNetConsoleData* pData) +bool CRConServer::CheckForBan(CConnectedNetConsoleData& pData) { - if (pData->m_bValidated) + if (pData.m_bValidated) { return false; } @@ -503,7 +503,7 @@ bool CRConServer::CheckForBan(CConnectedNetConsoleData* pData) } } - pData->m_bValidated = true; + pData.m_bValidated = true; // Check if IP is in the banned list. if (m_BannedList.find(szNetAdr) != m_BannedList.end()) @@ -512,14 +512,14 @@ bool CRConServer::CheckForBan(CConnectedNetConsoleData* pData) } // Check if netconsole has reached maximum number of attempts > add to banned list. - if (pData->m_nFailedAttempts >= sv_rcon_maxfailures->GetInt() - || pData->m_nIgnoredMessage >= sv_rcon_maxignores->GetInt()) + if (pData.m_nFailedAttempts >= sv_rcon_maxfailures->GetInt() + || pData.m_nIgnoredMessage >= sv_rcon_maxignores->GetInt()) { // Don't add white listed address to banned list. if (m_WhiteListAddress.CompareAdr(netAdr)) { - pData->m_nFailedAttempts = 0; - pData->m_nIgnoredMessage = 0; + pData.m_nFailedAttempts = 0; + pData.m_nIgnoredMessage = 0; return false; } @@ -545,8 +545,8 @@ void CRConServer::Disconnect(const char* szReason) // NETMGR //----------------------------------------------------------------------------- void CRConServer::Disconnect(const int nIndex, const char* szReason) // NETMGR { - CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(nIndex); - if (pData->m_bAuthorized || sv_rcon_debug->GetBool()) + CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(nIndex); + if (pData.m_bAuthorized || sv_rcon_debug->GetBool()) { // Inform server owner when authenticated connection has been closed. netadr_t netAdr = m_Socket.GetAcceptedSocketAddress(nIndex); @@ -570,9 +570,9 @@ void CRConServer::CloseNonAuthConnection(void) int nCount = m_Socket.GetAcceptedSocketCount(); for (int i = nCount - 1; i >= 0; i--) { - CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(i); + CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(i); - if (!pData->m_bAuthorized) + if (!pData.m_bAuthorized) { m_Socket.CloseAcceptedSocket(i); } diff --git a/r5dev/engine/server/sv_rcon.h b/r5dev/engine/server/sv_rcon.h index 35222c3e..0eb220bc 100644 --- a/r5dev/engine/server/sv_rcon.h +++ b/r5dev/engine/server/sv_rcon.h @@ -37,13 +37,13 @@ public: bool Serialize(vector& vecBuf, const char* pResponseMsg, const char* pResponseVal, const sv_rcon::response_t responseType, const int nMessageId = static_cast(eDLL_T::NETCON), const int nMessageType = static_cast(LogType_t::LOG_NET)) const; - void Authenticate(const cl_rcon::request& request, CConnectedNetConsoleData* pData); + void Authenticate(const cl_rcon::request& request, CConnectedNetConsoleData& pData); bool Comparator(const string& svPassword) const; virtual bool ProcessMessage(const char* pMsgBuf, const int nMsgLen) override; void Execute(const cl_rcon::request& request, const bool bConVar) const; - bool CheckForBan(CConnectedNetConsoleData* pData); + bool CheckForBan(CConnectedNetConsoleData& pData); virtual void Disconnect(const char* szReason = nullptr) override; void Disconnect(const int nIndex, const char* szReason = nullptr); diff --git a/r5dev/engine/shared/base_rcon.cpp b/r5dev/engine/shared/base_rcon.cpp index 6cc21764..d8117f69 100644 --- a/r5dev/engine/shared/base_rcon.cpp +++ b/r5dev/engine/shared/base_rcon.cpp @@ -69,23 +69,16 @@ bool CNetConBase::Send(const SocketHandle_t hSocket, const char* pMsgBuf, //----------------------------------------------------------------------------- // Purpose: receive message -// Input : *pData - +// Input : &pData - // nMaxLen - // Output: true on success, false otherwise //----------------------------------------------------------------------------- -void CNetConBase::Recv(CConnectedNetConsoleData* pData, const int nMaxLen) +void CNetConBase::Recv(CConnectedNetConsoleData& pData, const int nMaxLen) { - if (!pData) - { - Error(eDLL_T::ENGINE, NO_ERROR, "RCON Cmd: invalid input data\n"); - Assert(0); - return; - } - static char szRecvBuf[1024]; {////////////////////////////////////////////// - const int nPendingLen = ::recv(pData->m_hSocket, szRecvBuf, sizeof(char), MSG_PEEK); + const int nPendingLen = ::recv(pData.m_hSocket, szRecvBuf, sizeof(char), MSG_PEEK); if (nPendingLen == SOCKET_ERROR && m_Socket.IsSocketBlocking()) { return; @@ -98,7 +91,7 @@ void CNetConBase::Recv(CConnectedNetConsoleData* pData, const int nMaxLen) }////////////////////////////////////////////// int nReadLen = 0; // Find out how much we have to read. - int iResult = ::ioctlsocket(pData->m_hSocket, FIONREAD, reinterpret_cast(&nReadLen)); + int iResult = ::ioctlsocket(pData.m_hSocket, FIONREAD, reinterpret_cast(&nReadLen)); if (iResult == SOCKET_ERROR) { @@ -108,7 +101,7 @@ void CNetConBase::Recv(CConnectedNetConsoleData* pData, const int nMaxLen) while (nReadLen > 0) { - const int nRecvLen = ::recv(pData->m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), MSG_NOSIGNAL); + const int nRecvLen = ::recv(pData.m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), MSG_NOSIGNAL); if (nRecvLen == 0) // Socket was closed. { Disconnect("socket closed unexpectedly"); @@ -134,67 +127,67 @@ void CNetConBase::Recv(CConnectedNetConsoleData* pData, const int nMaxLen) // *pData - // Output: true on success, false otherwise //----------------------------------------------------------------------------- -bool CNetConBase::ProcessBuffer(CConnectedNetConsoleData* pData, +bool CNetConBase::ProcessBuffer(CConnectedNetConsoleData& pData, const char* pRecvBuf, int nRecvLen, const int nMaxLen) { bool bSuccess = true; while (nRecvLen > 0) { - if (pData->m_nPayloadLen) + if (pData.m_nPayloadLen) { - if (pData->m_nPayloadRead < pData->m_nPayloadLen) + if (pData.m_nPayloadRead < pData.m_nPayloadLen) { - pData->m_RecvBuffer[pData->m_nPayloadRead++] = *pRecvBuf; + pData.m_RecvBuffer[pData.m_nPayloadRead++] = *pRecvBuf; pRecvBuf++; nRecvLen--; } - if (pData->m_nPayloadRead == pData->m_nPayloadLen) + if (pData.m_nPayloadRead == pData.m_nPayloadLen) { if (!ProcessMessage( - reinterpret_cast(pData->m_RecvBuffer.data()), pData->m_nPayloadLen) + reinterpret_cast(pData.m_RecvBuffer.data()), pData.m_nPayloadLen) && bSuccess) { bSuccess = false; } - pData->m_nPayloadLen = 0; - pData->m_nPayloadRead = 0; + pData.m_nPayloadLen = 0; + pData.m_nPayloadRead = 0; } } - else if (pData->m_nPayloadRead+1 <= sizeof(int)) // Read size field. + else if (pData.m_nPayloadRead+1 <= sizeof(int)) // Read size field. { - pData->m_RecvBuffer[pData->m_nPayloadRead++] = *pRecvBuf; + pData.m_RecvBuffer[pData.m_nPayloadRead++] = *pRecvBuf; pRecvBuf++; nRecvLen--; } else // Build prefix. { - pData->m_nPayloadLen = int(ntohl(*reinterpret_cast(&pData->m_RecvBuffer[0]))); - pData->m_nPayloadRead = 0; + pData.m_nPayloadLen = int(ntohl(*reinterpret_cast(&pData.m_RecvBuffer[0]))); + pData.m_nPayloadRead = 0; - if (!pData->m_bAuthorized && nMaxLen > -1) + if (!pData.m_bAuthorized && nMaxLen > -1) { - if (pData->m_nPayloadLen > nMaxLen) + if (pData.m_nPayloadLen > nMaxLen) { Disconnect("overflow"); // Sending large messages while not authenticated. return false; } } - if (pData->m_nPayloadLen < 0 || - pData->m_nPayloadLen > pData->m_RecvBuffer.max_size()) + if (pData.m_nPayloadLen < 0 || + pData.m_nPayloadLen > pData.m_RecvBuffer.max_size()) { - Error(eDLL_T::ENGINE, NO_ERROR, "RCON Cmd: sync error (%d)\n", pData->m_nPayloadLen); + Error(eDLL_T::ENGINE, NO_ERROR, "RCON Cmd: sync error (%d)\n", pData.m_nPayloadLen); Disconnect("desync"); // Out of sync (irrecoverable). return false; } else { - pData->m_RecvBuffer.resize(pData->m_nPayloadLen); + pData.m_RecvBuffer.resize(pData.m_nPayloadLen); } } } diff --git a/r5dev/engine/shared/base_rcon.h b/r5dev/engine/shared/base_rcon.h index 35283ac4..5e370c5c 100644 --- a/r5dev/engine/shared/base_rcon.h +++ b/r5dev/engine/shared/base_rcon.h @@ -18,9 +18,9 @@ public: virtual void Disconnect(const char* szReason = nullptr) { NOTE_UNUSED(szReason); }; virtual bool Send(const SocketHandle_t hSocket, const char* pMsgBuf, const int nMsgLen) const; - virtual void Recv(CConnectedNetConsoleData* pData, const int nMaxLen = SOCKET_ERROR); + virtual void Recv(CConnectedNetConsoleData& pData, const int nMaxLen = SOCKET_ERROR); - virtual bool ProcessBuffer(CConnectedNetConsoleData* pData, const char* pRecvBuf, int nRecvLen, const int nMaxLen = SOCKET_ERROR); + virtual bool ProcessBuffer(CConnectedNetConsoleData& pData, const char* pRecvBuf, int nRecvLen, const int nMaxLen = SOCKET_ERROR); virtual bool ProcessMessage(const char* /*pMsgBuf*/, int /*nMsgLen*/) { return true; }; CSocketCreator* GetSocketCreator(void) { return &m_Socket; } diff --git a/r5dev/engine/shared/shared_rcon.cpp b/r5dev/engine/shared/shared_rcon.cpp index c2f7f3ce..3aba56c9 100644 --- a/r5dev/engine/shared/shared_rcon.cpp +++ b/r5dev/engine/shared/shared_rcon.cpp @@ -91,7 +91,7 @@ bool CL_NetConConnect(CNetConBase* pBase, const char* pHostAdr, const int nHostP //----------------------------------------------------------------------------- CConnectedNetConsoleData* SH_GetNetConData(CNetConBase* pBase, const int iSocket) { - const CSocketCreator* pCreator = pBase->GetSocketCreator(); + CSocketCreator* pCreator = pBase->GetSocketCreator(); Assert(iSocket >= 0 && (pCreator->GetAcceptedSocketCount() == 0 || iSocket < pCreator->GetAcceptedSocketCount())); @@ -100,7 +100,7 @@ CConnectedNetConsoleData* SH_GetNetConData(CNetConBase* pBase, const int iSocket return nullptr; } - return pCreator->GetAcceptedSocketData(iSocket); + return &pCreator->GetAcceptedSocketData(iSocket); } //----------------------------------------------------------------------------- diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index c3734240..03588b41 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -226,7 +226,7 @@ void CNetCon::RunFrame(void) { std::lock_guard l(m_Mutex); - CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(0); + CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(0); Recv(pData); } else if (m_bPromptConnect) diff --git a/r5dev/public/tier2/socketcreator.h b/r5dev/public/tier2/socketcreator.h index 91480d10..99a2a543 100644 --- a/r5dev/public/tier2/socketcreator.h +++ b/r5dev/public/tier2/socketcreator.h @@ -35,23 +35,23 @@ public: SocketHandle_t GetAcceptedSocketHandle(int nIndex) const; const netadr_t& GetAcceptedSocketAddress(int nIndex) const; - CConnectedNetConsoleData* GetAcceptedSocketData(int nIndex) const; + CConnectedNetConsoleData& GetAcceptedSocketData(int nIndex); + const CConnectedNetConsoleData& GetAcceptedSocketData(int nIndex) const; public: struct AcceptedSocket_t { - AcceptedSocket_t(void) - { - m_hSocket = NULL; - m_pData = nullptr; - } + AcceptedSocket_t(SocketHandle_t hSocket) + : m_hSocket(hSocket) + , m_Data(hSocket) + {} SocketHandle_t m_hSocket; netadr_t m_Address; - CConnectedNetConsoleData* m_pData; + CConnectedNetConsoleData m_Data; }; - std::vector m_hAcceptedSockets; + CUtlVector m_AcceptedSockets; SocketHandle_t m_hListenSocket; // Used to accept connections. private: diff --git a/r5dev/tier2/socketcreator.cpp b/r5dev/tier2/socketcreator.cpp index 76712bfc..e731d5fd 100644 --- a/r5dev/tier2/socketcreator.cpp +++ b/r5dev/tier2/socketcreator.cpp @@ -266,15 +266,12 @@ bool CSocketCreator::ConfigureSocket(SocketHandle_t hSocket, bool bDualStack /*= //----------------------------------------------------------------------------- int CSocketCreator::OnSocketAccepted(SocketHandle_t hSocket, const netadr_t& netAdr) { - AcceptedSocket_t newEntry; - - newEntry.m_hSocket = hSocket; + AcceptedSocket_t newEntry(hSocket); newEntry.m_Address = netAdr; - newEntry.m_pData = new CConnectedNetConsoleData(hSocket); - m_hAcceptedSockets.push_back(newEntry); + m_AcceptedSockets.AddToTail(newEntry); - int nIndex = static_cast(m_hAcceptedSockets.size()) - 1; + int nIndex = m_AcceptedSockets.Count() - 1; return nIndex; } @@ -284,17 +281,16 @@ int CSocketCreator::OnSocketAccepted(SocketHandle_t hSocket, const netadr_t& net //----------------------------------------------------------------------------- void CSocketCreator::CloseAcceptedSocket(int nIndex) { - if (nIndex >= int(m_hAcceptedSockets.size())) + if (nIndex >= m_AcceptedSockets.Count()) { Assert(0); return; } - AcceptedSocket_t& connected = m_hAcceptedSockets[nIndex]; + AcceptedSocket_t& connected = m_AcceptedSockets[nIndex]; DisconnectSocket(connected.m_hSocket); - delete connected.m_pData; - m_hAcceptedSockets.erase(m_hAcceptedSockets.begin() + nIndex); + m_AcceptedSockets.Remove(nIndex); } //----------------------------------------------------------------------------- @@ -302,14 +298,12 @@ void CSocketCreator::CloseAcceptedSocket(int nIndex) //----------------------------------------------------------------------------- void CSocketCreator::CloseAllAcceptedSockets(void) { - for (size_t i = 0; i < m_hAcceptedSockets.size(); ++i) + for (int i = 0; i < m_AcceptedSockets.Count(); ++i) { - AcceptedSocket_t& connected = m_hAcceptedSockets[i]; + AcceptedSocket_t& connected = m_AcceptedSockets[i]; DisconnectSocket(connected.m_hSocket); - - delete connected.m_pData; } - m_hAcceptedSockets.clear(); + m_AcceptedSockets.Purge(); } //----------------------------------------------------------------------------- @@ -338,9 +332,9 @@ int CSocketCreator::GetAuthorizedSocketCount(void) const { int ret = 0; - for (size_t i = 0; i < m_hAcceptedSockets.size(); ++i) + for (int i = 0; i < m_AcceptedSockets.Count(); ++i) { - if (m_hAcceptedSockets[i].m_pData->m_bAuthorized) + if (m_AcceptedSockets[i].m_Data.m_bAuthorized) { ret++; } @@ -355,7 +349,7 @@ int CSocketCreator::GetAuthorizedSocketCount(void) const //----------------------------------------------------------------------------- int CSocketCreator::GetAcceptedSocketCount(void) const { - return static_cast(m_hAcceptedSockets.size()); + return m_AcceptedSockets.Count(); } //----------------------------------------------------------------------------- @@ -365,8 +359,8 @@ int CSocketCreator::GetAcceptedSocketCount(void) const //----------------------------------------------------------------------------- SocketHandle_t CSocketCreator::GetAcceptedSocketHandle(int nIndex) const { - Assert(nIndex >= 0 && nIndex < int(m_hAcceptedSockets.size())); - return m_hAcceptedSockets[nIndex].m_hSocket; + Assert(nIndex >= 0 && nIndex < m_AcceptedSockets.Count()); + return m_AcceptedSockets[nIndex].m_hSocket; } //----------------------------------------------------------------------------- @@ -376,8 +370,8 @@ SocketHandle_t CSocketCreator::GetAcceptedSocketHandle(int nIndex) const //----------------------------------------------------------------------------- const netadr_t& CSocketCreator::GetAcceptedSocketAddress(int nIndex) const { - Assert(nIndex >= 0 && nIndex < int(m_hAcceptedSockets.size())); - return m_hAcceptedSockets[nIndex].m_Address; + Assert(nIndex >= 0 && nIndex < m_AcceptedSockets.Count()); + return m_AcceptedSockets[nIndex].m_Address; } //----------------------------------------------------------------------------- @@ -385,8 +379,19 @@ const netadr_t& CSocketCreator::GetAcceptedSocketAddress(int nIndex) const // Input : nIndex - // Output : CConnectedNetConsoleData* //----------------------------------------------------------------------------- -CConnectedNetConsoleData* CSocketCreator::GetAcceptedSocketData(int nIndex) const +CConnectedNetConsoleData& CSocketCreator::GetAcceptedSocketData(int nIndex) { - Assert(nIndex >= 0 && nIndex < int(m_hAcceptedSockets.size())); - return m_hAcceptedSockets[nIndex].m_pData; + Assert(nIndex >= 0 && nIndex < m_AcceptedSockets.Count()); + return m_AcceptedSockets[nIndex].m_Data; +} + +//----------------------------------------------------------------------------- +// Purpose: returns accepted socket data +// Input : nIndex - +// Output : CConnectedNetConsoleData* +//----------------------------------------------------------------------------- +const CConnectedNetConsoleData& CSocketCreator::GetAcceptedSocketData(int nIndex) const +{ + Assert(nIndex >= 0 && nIndex < m_AcceptedSockets.Count()); + return m_AcceptedSockets[nIndex].m_Data; } From 309e297ae4e8ba0b6b57ffc71157f6ac40989e92 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 10:49:39 +0200 Subject: [PATCH 04/24] Add 'Cmd_Dispatch' to SDK Signature is compatible with S1. --- r5dev/engine/cmd.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/r5dev/engine/cmd.h b/r5dev/engine/cmd.h index 7dbcb26a..0840ebc1 100644 --- a/r5dev/engine/cmd.h +++ b/r5dev/engine/cmd.h @@ -18,8 +18,11 @@ inline void(*Cbuf_AddText)(ECommandTarget_t eTarget, const char* pText, cmd_sour inline CMemory p_Cbuf_Execute; inline void(*Cbuf_Execute)(void); +inline CMemory p_Cmd_Dispatch; +inline void(*v_Cmd_Dispatch)(ECommandTarget_t eTarget, const ConCommandBase* pCmdBase, const CCommand* pCommand, bool bCallBackupCallback); + inline CMemory p_Cmd_ForwardToServer; -inline bool(*v_Cmd_ForwardToServer)(const CCommand* args); +inline bool(*v_Cmd_ForwardToServer)(const CCommand* pCommand); /////////////////////////////////////////////////////////////////////////////// class VCmd : public IDetour @@ -28,16 +31,20 @@ class VCmd : public IDetour { LogFunAdr("Cbuf_AddText", p_Cbuf_AddText.GetPtr()); LogFunAdr("Cbuf_Execute", p_Cbuf_Execute.GetPtr()); + LogFunAdr("Cmd_Dispatch", p_Cmd_Dispatch.GetPtr()); LogFunAdr("Cmd_ForwardToServer", p_Cmd_ForwardToServer.GetPtr()); } virtual void GetFun(void) const { p_Cbuf_AddText = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 63 D9 41 8B F8 48 8D 0D ?? ?? ?? ?? 48 8B F2 FF 15 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 41 B9 ?? ?? ?? ??"); p_Cbuf_Execute = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 FF 15 ?? ?? ?? ??"); + + p_Cmd_Dispatch = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 8B ?? 0C 49 FF C7").FollowNearCallSelf(); p_Cmd_ForwardToServer = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 44 8B 59 04"); Cbuf_AddText = p_Cbuf_AddText.RCast(); /*48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 63 D9 41 8B F8 48 8D 0D ?? ?? ?? ?? 48 8B F2 FF 15 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 41 B9 ?? ?? ?? ??*/ Cbuf_Execute = p_Cbuf_Execute.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 FF 15 ?? ?? ?? ??*/ + v_Cmd_Dispatch = p_Cmd_Dispatch.RCast(); v_Cmd_ForwardToServer = p_Cmd_ForwardToServer.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 44 8B 59 04*/ } virtual void GetVar(void) const { } From 10ee88ec10d773a1a6be3337d3fb681d62b06ba5 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 10:57:39 +0200 Subject: [PATCH 05/24] Fix RCON disconnect bug RCON occasionally did NOT disconnect, but only if the socket has been closed improperly. If the server/client crashes for example, the connection remained open in RCON; pendingLen on the initial peek recv < 0 while socket isn't blocking means socket has been closed unexpectedly. --- r5dev/engine/shared/base_rcon.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/r5dev/engine/shared/base_rcon.cpp b/r5dev/engine/shared/base_rcon.cpp index d8117f69..64aa9728 100644 --- a/r5dev/engine/shared/base_rcon.cpp +++ b/r5dev/engine/shared/base_rcon.cpp @@ -88,6 +88,11 @@ void CNetConBase::Recv(CConnectedNetConsoleData& pData, const int nMaxLen) Disconnect("remote closed socket"); return; } + else if (nPendingLen < 0) + { + Disconnect("socket closed unexpectedly"); + return; + } }////////////////////////////////////////////// int nReadLen = 0; // Find out how much we have to read. @@ -104,7 +109,7 @@ void CNetConBase::Recv(CConnectedNetConsoleData& pData, const int nMaxLen) const int nRecvLen = ::recv(pData.m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), MSG_NOSIGNAL); if (nRecvLen == 0) // Socket was closed. { - Disconnect("socket closed unexpectedly"); + Disconnect("socket closed"); break; } if (nRecvLen < 0 && !m_Socket.IsSocketBlocking()) From f6d262893794d1ac51d18e98ac00854a7fd3e766 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 11:20:24 +0200 Subject: [PATCH 06/24] Cleanup proto structure Removed unused/extraneous enumerants. --- r5dev/engine/server/sv_rcon.cpp | 23 +++++------------- r5dev/engine/server/sv_rcon.h | 2 +- r5dev/netconsole/netconsole.cpp | 9 +------ r5dev/protoc/cl_rcon.pb.cc | 34 +++++++++------------------ r5dev/protoc/cl_rcon.pb.h | 13 ++++------ r5dev/protoc/sv_rcon.pb.cc | 34 +++++++-------------------- r5dev/protoc/sv_rcon.pb.h | 12 ++++------ r5dev/resource/protobuf/cl_rcon.proto | 9 +++---- r5dev/resource/protobuf/sv_rcon.proto | 8 ++----- 9 files changed, 42 insertions(+), 102 deletions(-) diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index 2ca7736e..b5485b6b 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -416,15 +416,7 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) { if (pData.m_bAuthorized) // Only execute if auth was successful. { - Execute(request, false); - } - break; - } - case cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE: - { - if (pData.m_bAuthorized) - { - Execute(request, true); + Execute(request); } break; } @@ -432,6 +424,7 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) { if (pData.m_bAuthorized) { + // !TODO[ AMOS ]: Each netcon its own var??? sv_rcon_sendlogs->SetValue(request.requestval().c_str()); } break; @@ -448,17 +441,13 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) //----------------------------------------------------------------------------- // Purpose: execute commands issued from netconsole // Input : *request - -// bConVar - //----------------------------------------------------------------------------- -void CRConServer::Execute(const cl_rcon::request& request, const bool bConVar) const +void CRConServer::Execute(const cl_rcon::request& request) const { - if (bConVar) + ConVar* pConVar = g_pCVar->FindVar(request.requestmsg().c_str()); + if (pConVar) // Only run if this is a ConVar. { - ConVar* pConVar = g_pCVar->FindVar(request.requestmsg().c_str()); - if (pConVar) // Only run if this is a ConVar. - { - pConVar->SetValue(request.requestval().c_str()); - } + pConVar->SetValue(request.requestval().c_str()); } else // Execute command with "". { diff --git a/r5dev/engine/server/sv_rcon.h b/r5dev/engine/server/sv_rcon.h index 0eb220bc..e7c15688 100644 --- a/r5dev/engine/server/sv_rcon.h +++ b/r5dev/engine/server/sv_rcon.h @@ -42,7 +42,7 @@ public: virtual bool ProcessMessage(const char* pMsgBuf, const int nMsgLen) override; - void Execute(const cl_rcon::request& request, const bool bConVar) const; + void Execute(const cl_rcon::request& request) const; bool CheckForBan(CConnectedNetConsoleData& pData); virtual void Disconnect(const char* szReason = nullptr) override; diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index 03588b41..df019390 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -130,6 +130,7 @@ void CNetCon::UserInput(void) return; } + // !TODO[ AMOS ]: Swap out with CCommand! const vector vSubStrings = StringSplit(m_Input, ' ', 2); vector vecMsg; @@ -143,14 +144,6 @@ void CNetCon::UserInput(void) bSend = Serialize(vecMsg, vSubStrings[1].c_str(), "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); } - else if (vSubStrings[0].compare("SET") == 0) // Set value query. - { - if (vSubStrings.size() > 2) - { - bSend = Serialize(vecMsg, vSubStrings[1].c_str(), vSubStrings[2].c_str(), - cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE); - } - } else // Execute command query. { bSend = Serialize(vecMsg, m_Input.c_str(), "", diff --git a/r5dev/protoc/cl_rcon.pb.cc b/r5dev/protoc/cl_rcon.pb.cc index 9855f349..c577a653 100644 --- a/r5dev/protoc/cl_rcon.pb.cc +++ b/r5dev/protoc/cl_rcon.pb.cc @@ -43,41 +43,29 @@ bool request_t_IsValid(int value) { case 0: case 1: case 2: - case 3: - case 4: - case 5: return true; default: return false; } } -static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed request_t_strings[6] = {}; +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed request_t_strings[3] = {}; static const char request_t_names[] = "SERVERDATA_REQUEST_AUTH" "SERVERDATA_REQUEST_EXECCOMMAND" - "SERVERDATA_REQUEST_SEND_CONSOLE_LOG" - "SERVERDATA_REQUEST_SEND_REMOTEBUG" - "SERVERDATA_REQUEST_SETVALUE" - "SERVERDATA_REQUEST_VALUE"; + "SERVERDATA_REQUEST_SEND_CONSOLE_LOG"; static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry request_t_entries[] = { - { {request_t_names + 0, 23}, 3 }, - { {request_t_names + 23, 30}, 2 }, - { {request_t_names + 53, 35}, 4 }, - { {request_t_names + 88, 33}, 5 }, - { {request_t_names + 121, 27}, 1 }, - { {request_t_names + 148, 24}, 0 }, + { {request_t_names + 0, 23}, 1 }, + { {request_t_names + 23, 30}, 0 }, + { {request_t_names + 53, 35}, 2 }, }; static const int request_t_entries_by_number[] = { - 5, // 0 -> SERVERDATA_REQUEST_VALUE - 4, // 1 -> SERVERDATA_REQUEST_SETVALUE - 1, // 2 -> SERVERDATA_REQUEST_EXECCOMMAND - 0, // 3 -> SERVERDATA_REQUEST_AUTH - 2, // 4 -> SERVERDATA_REQUEST_SEND_CONSOLE_LOG - 3, // 5 -> SERVERDATA_REQUEST_SEND_REMOTEBUG + 1, // 0 -> SERVERDATA_REQUEST_EXECCOMMAND + 0, // 1 -> SERVERDATA_REQUEST_AUTH + 2, // 2 -> SERVERDATA_REQUEST_SEND_CONSOLE_LOG }; const std::string& request_t_Name( @@ -86,12 +74,12 @@ const std::string& request_t_Name( ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( request_t_entries, request_t_entries_by_number, - 6, request_t_strings); + 3, request_t_strings); (void) dummy; int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( request_t_entries, request_t_entries_by_number, - 6, value); + 3, value); return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : request_t_strings[idx].get(); } @@ -99,7 +87,7 @@ bool request_t_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, request_t* value) { int int_value; bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( - request_t_entries, 6, name, &int_value); + request_t_entries, 3, name, &int_value); if (success) { *value = static_cast(int_value); } diff --git a/r5dev/protoc/cl_rcon.pb.h b/r5dev/protoc/cl_rcon.pb.h index a1c4982b..55fd5689 100644 --- a/r5dev/protoc/cl_rcon.pb.h +++ b/r5dev/protoc/cl_rcon.pb.h @@ -53,18 +53,15 @@ PROTOBUF_NAMESPACE_CLOSE namespace cl_rcon { enum request_t : int { - SERVERDATA_REQUEST_VALUE = 0, - SERVERDATA_REQUEST_SETVALUE = 1, - SERVERDATA_REQUEST_EXECCOMMAND = 2, - SERVERDATA_REQUEST_AUTH = 3, - SERVERDATA_REQUEST_SEND_CONSOLE_LOG = 4, - SERVERDATA_REQUEST_SEND_REMOTEBUG = 5, + SERVERDATA_REQUEST_EXECCOMMAND = 0, + SERVERDATA_REQUEST_AUTH = 1, + SERVERDATA_REQUEST_SEND_CONSOLE_LOG = 2, request_t_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits::min(), request_t_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits::max() }; bool request_t_IsValid(int value); -constexpr request_t request_t_MIN = SERVERDATA_REQUEST_VALUE; -constexpr request_t request_t_MAX = SERVERDATA_REQUEST_SEND_REMOTEBUG; +constexpr request_t request_t_MIN = SERVERDATA_REQUEST_EXECCOMMAND; +constexpr request_t request_t_MAX = SERVERDATA_REQUEST_SEND_CONSOLE_LOG; constexpr int request_t_ARRAYSIZE = request_t_MAX + 1; const std::string& request_t_Name(request_t value); diff --git a/r5dev/protoc/sv_rcon.pb.cc b/r5dev/protoc/sv_rcon.pb.cc index f983f6ce..4ef8824c 100644 --- a/r5dev/protoc/sv_rcon.pb.cc +++ b/r5dev/protoc/sv_rcon.pb.cc @@ -42,42 +42,26 @@ bool response_t_IsValid(int value) { switch (value) { case 0: case 1: - case 2: - case 3: - case 4: - case 5: return true; default: return false; } } -static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed response_t_strings[6] = {}; +static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed response_t_strings[2] = {}; static const char response_t_names[] = "SERVERDATA_RESPONSE_AUTH" - "SERVERDATA_RESPONSE_CONSOLE_LOG" - "SERVERDATA_RESPONSE_REMOTEBUG" - "SERVERDATA_RESPONSE_STRING" - "SERVERDATA_RESPONSE_UPDATE" - "SERVERDATA_RESPONSE_VALUE"; + "SERVERDATA_RESPONSE_CONSOLE_LOG"; static const ::PROTOBUF_NAMESPACE_ID::internal::EnumEntry response_t_entries[] = { - { {response_t_names + 0, 24}, 2 }, - { {response_t_names + 24, 31}, 3 }, - { {response_t_names + 55, 29}, 5 }, - { {response_t_names + 84, 26}, 4 }, - { {response_t_names + 110, 26}, 1 }, - { {response_t_names + 136, 25}, 0 }, + { {response_t_names + 0, 24}, 0 }, + { {response_t_names + 24, 31}, 1 }, }; static const int response_t_entries_by_number[] = { - 5, // 0 -> SERVERDATA_RESPONSE_VALUE - 4, // 1 -> SERVERDATA_RESPONSE_UPDATE - 0, // 2 -> SERVERDATA_RESPONSE_AUTH - 1, // 3 -> SERVERDATA_RESPONSE_CONSOLE_LOG - 3, // 4 -> SERVERDATA_RESPONSE_STRING - 2, // 5 -> SERVERDATA_RESPONSE_REMOTEBUG + 0, // 0 -> SERVERDATA_RESPONSE_AUTH + 1, // 1 -> SERVERDATA_RESPONSE_CONSOLE_LOG }; const std::string& response_t_Name( @@ -86,12 +70,12 @@ const std::string& response_t_Name( ::PROTOBUF_NAMESPACE_ID::internal::InitializeEnumStrings( response_t_entries, response_t_entries_by_number, - 6, response_t_strings); + 2, response_t_strings); (void) dummy; int idx = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumName( response_t_entries, response_t_entries_by_number, - 6, value); + 2, value); return idx == -1 ? ::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString() : response_t_strings[idx].get(); } @@ -99,7 +83,7 @@ bool response_t_Parse( ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, response_t* value) { int int_value; bool success = ::PROTOBUF_NAMESPACE_ID::internal::LookUpEnumValue( - response_t_entries, 6, name, &int_value); + response_t_entries, 2, name, &int_value); if (success) { *value = static_cast(int_value); } diff --git a/r5dev/protoc/sv_rcon.pb.h b/r5dev/protoc/sv_rcon.pb.h index 06e6e38d..3d179775 100644 --- a/r5dev/protoc/sv_rcon.pb.h +++ b/r5dev/protoc/sv_rcon.pb.h @@ -53,18 +53,14 @@ PROTOBUF_NAMESPACE_CLOSE namespace sv_rcon { enum response_t : int { - SERVERDATA_RESPONSE_VALUE = 0, - SERVERDATA_RESPONSE_UPDATE = 1, - SERVERDATA_RESPONSE_AUTH = 2, - SERVERDATA_RESPONSE_CONSOLE_LOG = 3, - SERVERDATA_RESPONSE_STRING = 4, - SERVERDATA_RESPONSE_REMOTEBUG = 5, + SERVERDATA_RESPONSE_AUTH = 0, + SERVERDATA_RESPONSE_CONSOLE_LOG = 1, response_t_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits::min(), response_t_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits::max() }; bool response_t_IsValid(int value); -constexpr response_t response_t_MIN = SERVERDATA_RESPONSE_VALUE; -constexpr response_t response_t_MAX = SERVERDATA_RESPONSE_REMOTEBUG; +constexpr response_t response_t_MIN = SERVERDATA_RESPONSE_AUTH; +constexpr response_t response_t_MAX = SERVERDATA_RESPONSE_CONSOLE_LOG; constexpr int response_t_ARRAYSIZE = response_t_MAX + 1; const std::string& response_t_Name(response_t value); diff --git a/r5dev/resource/protobuf/cl_rcon.proto b/r5dev/resource/protobuf/cl_rcon.proto index fbcba545..c0a0907c 100644 --- a/r5dev/resource/protobuf/cl_rcon.proto +++ b/r5dev/resource/protobuf/cl_rcon.proto @@ -4,12 +4,9 @@ option optimize_for = LITE_RUNTIME; enum request_t { - SERVERDATA_REQUEST_VALUE = 0; - SERVERDATA_REQUEST_SETVALUE = 1; - SERVERDATA_REQUEST_EXECCOMMAND = 2; - SERVERDATA_REQUEST_AUTH = 3; - SERVERDATA_REQUEST_SEND_CONSOLE_LOG = 4; - SERVERDATA_REQUEST_SEND_REMOTEBUG = 5; + SERVERDATA_REQUEST_EXECCOMMAND = 0; + SERVERDATA_REQUEST_AUTH = 1; + SERVERDATA_REQUEST_SEND_CONSOLE_LOG = 2; } message request diff --git a/r5dev/resource/protobuf/sv_rcon.proto b/r5dev/resource/protobuf/sv_rcon.proto index 9666dc48..3a64cfbc 100644 --- a/r5dev/resource/protobuf/sv_rcon.proto +++ b/r5dev/resource/protobuf/sv_rcon.proto @@ -4,12 +4,8 @@ option optimize_for = LITE_RUNTIME; enum response_t { - SERVERDATA_RESPONSE_VALUE = 0; - SERVERDATA_RESPONSE_UPDATE = 1; - SERVERDATA_RESPONSE_AUTH = 2; - SERVERDATA_RESPONSE_CONSOLE_LOG = 3; - SERVERDATA_RESPONSE_STRING = 4; - SERVERDATA_RESPONSE_REMOTEBUG = 5; + SERVERDATA_RESPONSE_AUTH = 0; + SERVERDATA_RESPONSE_CONSOLE_LOG = 1; } message response From ce4b7b84a86feaf9634d79cd33e1af682042ab61 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 11:53:46 +0200 Subject: [PATCH 07/24] Promote RCON command execution authority Allow RCON to execute any commands and set any cvar, regardless of their flags. --- r5dev/common/callback.cpp | 8 +++++--- r5dev/engine/server/sv_rcon.cpp | 29 ++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/r5dev/common/callback.cpp b/r5dev/common/callback.cpp index 87229496..52c284d3 100644 --- a/r5dev/common/callback.cpp +++ b/r5dev/common/callback.cpp @@ -909,7 +909,9 @@ RCON_CmdQuery_f */ void RCON_CmdQuery_f(const CCommand& args) { - if (args.ArgC() < 2) + const int64_t argCount = args.ArgC(); + + if (argCount < 2) { const char* pszAddress = rcon_address->GetString(); @@ -935,7 +937,7 @@ void RCON_CmdQuery_f(const CCommand& args) if (strcmp(args.Arg(1), "PASS") == 0) // Auth with RCON server using rcon_password ConVar value. { - if (args.ArgC() > 2) + if (argCount > 2) { bSuccess = RCONClient()->Serialize(vecMsg, args.Arg(2), "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); } @@ -957,7 +959,7 @@ void RCON_CmdQuery_f(const CCommand& args) return; } - bSuccess = RCONClient()->Serialize(vecMsg, args.ArgS(), "", cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); + bSuccess = RCONClient()->Serialize(vecMsg, args.Arg(1), args.ArgS(), cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); if (bSuccess) { RCONClient()->Send(hSocket, vecMsg.data(), int(vecMsg.size())); diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index b5485b6b..4a81a070 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -439,19 +439,34 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) } //----------------------------------------------------------------------------- -// Purpose: execute commands issued from netconsole -// Input : *request - +// Purpose: execute commands issued from netconsole (ignores all protection flags) +// Input : &request - //----------------------------------------------------------------------------- void CRConServer::Execute(const cl_rcon::request& request) const { - ConVar* pConVar = g_pCVar->FindVar(request.requestmsg().c_str()); - if (pConVar) // Only run if this is a ConVar. + const char* pCommandString = request.requestmsg().c_str(); + ConCommandBase* pCommandBase = g_pCVar->FindCommandBase(pCommandString); + + if (!pCommandBase) { - pConVar->SetValue(request.requestval().c_str()); + // Found nothing. + return; } - else // Execute command with "". + + const bool isCommand = pCommandBase->IsCommand(); + const char* pValueString = request.requestval().c_str(); + + if (!isCommand) { - Cbuf_AddText(Cbuf_GetCurrentPlayer(), request.requestmsg().c_str(), cmd_source_t::kCommandSrcCode); + ConVar* pConVar = reinterpret_cast(pCommandBase); + pConVar->SetValue(pValueString); + } + else // Invoke command callback directly. + { + CCommand cmd; + cmd.Tokenize(pValueString, cmd_source_t::kCommandSrcCode); + + v_Cmd_Dispatch(ECommandTarget_t::CBUF_SERVER, pCommandBase, &cmd, false); } } From dbe75c07097bff090cd714222453846141d3abe5 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 12:44:46 +0200 Subject: [PATCH 08/24] Make private No reason to be public. --- r5dev/public/tier2/socketcreator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/r5dev/public/tier2/socketcreator.h b/r5dev/public/tier2/socketcreator.h index 99a2a543..1520bd3e 100644 --- a/r5dev/public/tier2/socketcreator.h +++ b/r5dev/public/tier2/socketcreator.h @@ -51,10 +51,10 @@ public: CConnectedNetConsoleData m_Data; }; +private: CUtlVector m_AcceptedSockets; SocketHandle_t m_hListenSocket; // Used to accept connections. -private: enum { SOCKET_TCP_MAX_ACCEPTS = 2 From 26c10dfd11221c226ad51b0be40db06905217e07 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 14:32:06 +0200 Subject: [PATCH 09/24] Restructure concommandbase classes Move all classes deriving from ConCommandBase to a single file, and split out CCommand, CCvar, CCvarUtilities etc to their own files. This makes it possible to use CCommand and stuff in external tools without linker errors/warnings. --- r5dev/core/init.cpp | 2 +- r5dev/public/iconcommand.h | 18 + r5dev/public/icvar.h | 1 + r5dev/public/tier1/cmd.h | 155 +------- r5dev/public/tier1/convar.h | 302 +++++++++++++++ r5dev/public/tier1/cvar.h | 315 ++++------------ r5dev/tier1/CMakeLists.txt | 1 + r5dev/tier1/cmd.cpp | 87 ----- r5dev/tier1/convar.cpp | 497 +++++++++++++++++++++++++ r5dev/tier1/cvar.cpp | 606 +------------------------------ r5dev/vstdlib/CMakeLists.txt | 1 + r5dev/vstdlib/concommandhash.cpp | 211 +++++++++++ r5dev/vstdlib/concommandhash.h | 2 +- 13 files changed, 1117 insertions(+), 1081 deletions(-) create mode 100644 r5dev/public/tier1/convar.h create mode 100644 r5dev/tier1/convar.cpp create mode 100644 r5dev/vstdlib/concommandhash.cpp diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index bac2e2ac..3e843127 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -448,7 +448,7 @@ void DetourRegister() // Register detour classes to be searched and hooked. // Tier1 REGISTER(VCommandLine); - REGISTER(VConCommand); + REGISTER(VConVar); REGISTER(VCVar); // VPC diff --git a/r5dev/public/iconcommand.h b/r5dev/public/iconcommand.h index 6181c373..af3bcb78 100644 --- a/r5dev/public/iconcommand.h +++ b/r5dev/public/iconcommand.h @@ -2,6 +2,24 @@ #define ICONCOMMAND_H #include "icvar.h" +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ConCommandBase; +class CCommand; + +//----------------------------------------------------------------------------- +// Any executable that wants to use ConVars need to implement one of +// these to hook up access to console variables. +//----------------------------------------------------------------------------- +abstract_class IConCommandBaseAccessor +{ +public: + // Flags is a combination of FCVAR flags in cvar.h. + // hOut is filled in with a handle to the variable. + virtual bool RegisterConCommandBase(ConCommandBase* pVar) = 0; +}; + //----------------------------------------------------------------------------- // Abstract interface for ConVars //----------------------------------------------------------------------------- diff --git a/r5dev/public/icvar.h b/r5dev/public/icvar.h index 76b1bd23..c40ff880 100644 --- a/r5dev/public/icvar.h +++ b/r5dev/public/icvar.h @@ -1,6 +1,7 @@ #ifndef ICVAR_H #define ICVAR_H #include "tier0/annotations.h" +#include "iconvar.h" #include "appframework/IAppSystem.h" //----------------------------------------------------------------------------- diff --git a/r5dev/public/tier1/cmd.h b/r5dev/public/tier1/cmd.h index cd35ff6c..9b9eff5b 100644 --- a/r5dev/public/tier1/cmd.h +++ b/r5dev/public/tier1/cmd.h @@ -12,29 +12,7 @@ #ifndef TIER1_CMD_H #define TIER1_CMD_H -#include "tier1/utlvector.h" -#include "tier1/utlstring.h" #include "tier1/characterset.h" -#include "public/iconvar.h" -#include "public/iconcommand.h" -#include "mathlib/color.h" - -//----------------------------------------------------------------------------- -// Forward declarations -//----------------------------------------------------------------------------- -class ConCommandBase; - -//----------------------------------------------------------------------------- -// Any executable that wants to use ConVars need to implement one of -// these to hook up access to console variables. -//----------------------------------------------------------------------------- -class IConCommandBaseAccessor -{ -public: - // Flags is a combination of FCVAR flags in cvar.h. - // hOut is filled in with a handle to the variable. - virtual bool RegisterConCommandBase(ConCommandBase* pVar) = 0; -}; //----------------------------------------------------------------------------- // Purpose: Command buffer context @@ -77,7 +55,7 @@ private: public: CCommand(); CCommand(int nArgC, const char** ppArgV, cmd_source_t source); - bool Tokenize(const char* pCommand, cmd_source_t source, characterset_t* pBreakSet = nullptr); + bool Tokenize(const char* pCommand, cmd_source_t source = cmd_source_t::kCommandSrcCode, characterset_t* pBreakSet = nullptr); int64_t ArgC(void) const; const char** ArgV(void) const; @@ -99,135 +77,4 @@ private: const char* m_ppArgv[COMMAND_MAX_ARGC]; }; -//----------------------------------------------------------------------------- -// Purpose: The base console invoked command/cvar interface -//----------------------------------------------------------------------------- -class ConCommandBase -{ -public: - virtual ~ConCommandBase(void) { }; - - virtual bool IsCommand(void) const = 0; - virtual bool IsFlagSet(int nFlags) const = 0; - - virtual void AddFlags(int nFlags) = 0; - virtual void RemoveFlags(int nFlags) = 0; - - virtual int GetFlags(void) const = 0; - virtual const char* GetName(void) const = 0; - virtual const char* GetHelpText(void) const = 0; - virtual const char* GetUsageText(void) const = 0; - - virtual void SetAccessor(IConCommandBaseAccessor* pAccessor) = 0; - virtual bool IsRegistered(void) const = 0; - - virtual int GetDLLIdentifier() const = 0; - virtual ConCommandBase* Create (const char* szName, const char* szHelpString, - int nFlags, const char* pszUsageString) = 0; - - virtual void Init() = 0; - - bool HasFlags(int nFlags) const; - - ConCommandBase* GetNext(void) const; - char* CopyString(const char* szFrom) const; - - ConCommandBase* m_pNext; //0x0008 - bool m_bRegistered; //0x0010 - const char* m_pszName; //0x0018 - const char* m_pszHelpString; //0x0020 - const char* m_pszUsageString; //0x0028 - IConCommandBaseAccessor* s_pAccessor; //0x0030 <-- unused since executable is monolithic. - int m_nFlags; //0x0038 -}; //Size: 0x0040 -static_assert(sizeof(ConCommandBase) == 0x40); - -//----------------------------------------------------------------------------- -// Purpose: The console invoked command -//----------------------------------------------------------------------------- -class ConCommand : public ConCommandBase -{ - friend class CCvar; -public: - ConCommand(void); - - static ConCommand* StaticCreate(const char* szName, const char* szHelpString, const char* pszUsageString, - int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCommandCompletionCallback); - - virtual int AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands) = 0; - virtual bool CanAutoComplete(void) const = 0; - - void* m_nNullCallBack; //0x0040 - void* m_pSubCallback; //0x0048 - // Call this function when executing the command - union - { - FnCommandCallbackV1_t m_fnCommandCallbackV1; - FnCommandCallback_t m_fnCommandCallback; - ICommandCallback* m_pCommandCallback; - }; - - union - { - FnCommandCompletionCallback m_fnCompletionCallback; - ICommandCompletionCallback* m_pCommandCompletionCallback; - }; - - bool m_bHasCompletionCallback : 1; - bool m_bUsingNewCommandCallback : 1; - bool m_bUsingCommandCallbackInterface : 1; -}; - -/* ==== CONCOMMAND ====================================================================================================================================================== */ -inline CMemory p_ConCommand_AutoCompleteSuggest; -inline bool(*ConCommand_AutoCompleteSuggest)(ConCommand* pCommand, const char* partial, CUtlVector< CUtlString >& commands); - -inline CMemory p_ConCommandBase_IsFlagSet; -inline bool(*ConCommandBase_IsFlagSet)(ConCommandBase* pCommand, int nFlag); - -inline CMemory p_NullSub; -inline void(*NullSub)(void); - -inline CMemory p_CallbackStub; -inline FnCommandCompletionCallback CallbackStub; - -inline ConCommandBase* g_pConCommandVFTable; - -/////////////////////////////////////////////////////////////////////////////// -ECommandTarget_t Cbuf_GetCurrentPlayer(void); - -/////////////////////////////////////////////////////////////////////////////// -class VConCommand : public IDetour -{ - virtual void GetAdr(void) const - { - LogFunAdr("ConCommandBase::IsFlagSet", p_ConCommandBase_IsFlagSet.GetPtr()); - LogFunAdr("ConCommand::AutoCompleteSuggest", p_ConCommand_AutoCompleteSuggest.GetPtr()); - LogFunAdr("CallbackStub", p_CallbackStub.GetPtr()); - LogFunAdr("NullSub", p_NullSub.GetPtr()); - } - virtual void GetFun(void) const - { - p_ConCommand_AutoCompleteSuggest = g_GameDll.FindPatternSIMD("40 ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 F6 41 60 04"); - p_ConCommandBase_IsFlagSet = g_GameDll.FindPatternSIMD("85 51 38 0F 95 C0 C3"); - - p_NullSub = g_GameDll.FindPatternSIMD("C2 ?? ?? CC CC CC CC CC CC CC CC CC CC CC CC CC 40 53 48 83 EC 20 48 8D 05 ?? ?? ?? ??"); - p_CallbackStub = g_GameDll.FindPatternSIMD("33 C0 C3 CC CC CC CC CC CC CC CC CC CC CC CC CC 80 49 68 08"); - - ConCommandBase_IsFlagSet = p_ConCommandBase_IsFlagSet.RCast(); /*85 51 38 0F 95 C0 C3*/ - ConCommand_AutoCompleteSuggest = p_ConCommand_AutoCompleteSuggest.RCast&)>(); - - NullSub = p_NullSub.RCast(); /*C2 00 00 CC CC CC CC CC CC CC CC CC CC CC CC CC 40 53 48 83 EC 20 48 8D 05 ?? ?? ?? ??*/ - CallbackStub = p_CallbackStub.RCast(); /*33 C0 C3 CC CC CC CC CC CC CC CC CC CC CC CC CC 80 49 68 08*/ /*UserMathErrorFunction*/ - } - virtual void GetVar(void) const { } - virtual void GetCon(void) const - { - g_pConCommandVFTable = g_GameDll.GetVirtualMethodTable(".?AVConCommand@@").RCast(); - } - virtual void Attach(void) const { }; - virtual void Detach(void) const { }; -}; -/////////////////////////////////////////////////////////////////////////////// - #endif // TIER1_CMD_H diff --git a/r5dev/public/tier1/convar.h b/r5dev/public/tier1/convar.h new file mode 100644 index 00000000..34a26775 --- /dev/null +++ b/r5dev/public/tier1/convar.h @@ -0,0 +1,302 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $NoKeywords: $ +//===========================================================================// + +#ifndef CONVAR_H +#define CONVAR_H + +#include "mathlib/color.h" +#include "public/iconvar.h" +#include "public/iconcommand.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" + +//----------------------------------------------------------------------------- +// Purpose: The base console invoked command/cvar interface +//----------------------------------------------------------------------------- +class ConCommandBase +{ +public: + virtual ~ConCommandBase(void) { }; + + virtual bool IsCommand(void) const = 0; + virtual bool IsFlagSet(int nFlags) const = 0; + + virtual void AddFlags(int nFlags) = 0; + virtual void RemoveFlags(int nFlags) = 0; + + virtual int GetFlags(void) const = 0; + virtual const char* GetName(void) const = 0; + virtual const char* GetHelpText(void) const = 0; + virtual const char* GetUsageText(void) const = 0; + + virtual void SetAccessor(IConCommandBaseAccessor* pAccessor) = 0; + virtual bool IsRegistered(void) const = 0; + + virtual int GetDLLIdentifier() const = 0; + virtual ConCommandBase* Create(const char* szName, const char* szHelpString, + int nFlags, const char* pszUsageString) = 0; + + virtual void Init() = 0; + + bool HasFlags(int nFlags) const; + + ConCommandBase* GetNext(void) const; + char* CopyString(const char* szFrom) const; + + ConCommandBase* m_pNext; //0x0008 + bool m_bRegistered; //0x0010 + const char* m_pszName; //0x0018 + const char* m_pszHelpString; //0x0020 + const char* m_pszUsageString; //0x0028 + IConCommandBaseAccessor* s_pAccessor; //0x0030 <-- unused since executable is monolithic. + int m_nFlags; //0x0038 +}; +static_assert(sizeof(ConCommandBase) == 0x40); + +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// Purpose: The console invoked command +//----------------------------------------------------------------------------- +class ConCommand : public ConCommandBase +{ + friend class CCvar; +public: + ConCommand(void); + + static ConCommand* StaticCreate(const char* szName, const char* szHelpString, const char* pszUsageString, + int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCommandCompletionCallback); + + virtual int AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands) = 0; + virtual bool CanAutoComplete(void) const = 0; + + void* m_nNullCallBack; //0x0040 + void* m_pSubCallback; //0x0048 + // Call this function when executing the command + union + { + FnCommandCallbackV1_t m_fnCommandCallbackV1; + FnCommandCallback_t m_fnCommandCallback; + ICommandCallback* m_pCommandCallback; + }; + + union + { + FnCommandCompletionCallback m_fnCompletionCallback; + ICommandCompletionCallback* m_pCommandCompletionCallback; + }; + + bool m_bHasCompletionCallback : 1; + bool m_bUsingNewCommandCallback : 1; + bool m_bUsingCommandCallbackInterface : 1; +}; +static_assert(sizeof(ConCommand) == 0x68); + +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// Purpose: A console variable +//----------------------------------------------------------------------------- +class ConVar : public ConCommandBase, public IConVar +{ + friend class CCvar; + friend class ConVarRef; + +public: + static ConVar* StaticCreate(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, + bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); + void Destroy(void); + + ConVar(void); + virtual ~ConVar(void) { }; + + FORCEINLINE bool GetBool(void) const; + FORCEINLINE float GetFloat(void) const; + FORCEINLINE double GetDouble(void) const; + FORCEINLINE int GetInt(void) const; + FORCEINLINE Color GetColor(void) const; + FORCEINLINE const char* GetString(void) const; + + void SetMax(float flMaxValue); + void SetMin(float flMinValue); + bool GetMin(float& flMinValue) const; + bool GetMax(float& flMaxValue) const; + float GetMinValue(void) const; + float GetMaxValue(void) const; + bool HasMin(void) const; + bool HasMax(void) const; + + void SetValue(int nValue); + void SetValue(float flValue); + void SetValue(const char* pszValue); + void SetValue(Color clValue); + + virtual void InternalSetValue(const char* pszValue) = 0; + virtual void InternalSetFloatValue(float flValue) = 0; + virtual void InternalSetIntValue(int nValue) = 0; + void InternalSetColorValue(Color value); + + virtual __int64 Unknown0(unsigned int a2) = 0; + virtual __int64 Unknown1(const char* a2) = 0; + + void Revert(void); + virtual bool ClampValue(float& flValue) = 0; + + const char* GetDefault(void) const; + void SetDefault(const char* pszDefault); + bool SetColorFromString(const char* pszValue); + + virtual void ChangeStringValue(const char* pszTempValue) = 0; + virtual void CreateInternal(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, + bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString) = 0; + + void InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke); + void RemoveChangeCallback(FnChangeCallback_t callback); + + struct CVValue_t + { + char* m_pszString; + size_t m_iStringLength; + float m_fValue; + int m_nValue; + }; + + ConVar* m_pParent; //0x0048 + const char* m_pszDefaultValue; //0x0050 + CVValue_t m_Value; //0c0058 + bool m_bHasMin; //0x0070 + float m_fMinVal; //0x0074 + bool m_bHasMax; //0x0078 + float m_fMaxVal; //0x007C + CUtlVector m_fnChangeCallbacks; //0x0080 +}; +static_assert(sizeof(ConVar) == 0xA0); + +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a boolean. +// Output : bool +//----------------------------------------------------------------------------- +FORCEINLINE bool ConVar::GetBool(void) const +{ + return !!GetInt(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float. +// Output : float +//----------------------------------------------------------------------------- +FORCEINLINE float ConVar::GetFloat(void) const +{ + return m_pParent->m_Value.m_fValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a double. +// Output : double +//----------------------------------------------------------------------------- +FORCEINLINE double ConVar::GetDouble(void) const +{ + return static_cast(m_pParent->m_Value.m_fValue); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an integer. +// Output : int +//----------------------------------------------------------------------------- +FORCEINLINE int ConVar::GetInt(void) const +{ + return m_pParent->m_Value.m_nValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a color. +// Output : Color +//----------------------------------------------------------------------------- +FORCEINLINE Color ConVar::GetColor(void) const +{ + unsigned char* pColorElement = (reinterpret_cast(&m_pParent->m_Value.m_nValue)); + return Color(pColorElement[0], pColorElement[1], pColorElement[2], pColorElement[3]); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string. +// Output : const char * +//----------------------------------------------------------------------------- +FORCEINLINE const char* ConVar::GetString(void) const +{ + if (m_nFlags & FCVAR_NEVER_AS_STRING) + { + return "FCVAR_NEVER_AS_STRING"; + } + + char const* str = m_pParent->m_Value.m_pszString; + return str ? str : ""; +} + +/* ==== CONVAR ========================================================================================================================================================== */ +inline CMemory p_ConVar_Register; +inline void*(*v_ConVar_Register)(ConVar* thisptr, const char* szName, const char* szDefaultValue, int nFlags, const char* szHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); + +inline CMemory p_ConVar_Unregister; +inline void(*v_ConVar_Unregister)(ConVar* thisptr); + +inline CMemory p_ConVar_IsFlagSet; +inline bool(*v_ConVar_IsFlagSet)(ConVar* pConVar, int nFlag); + +inline ConCommandBase* g_pConCommandBaseVFTable; +inline ConCommand* g_pConCommandVFTable; +inline ConVar* g_pConVarVBTable; +inline IConVar* g_pConVarVFTable; + +/////////////////////////////////////////////////////////////////////////////// +class VConVar : public IDetour +{ + virtual void GetAdr(void) const + { + LogConAdr("ConCommandBase::`vftable'", reinterpret_cast(g_pConCommandBaseVFTable)); + LogConAdr("ConCommand::`vftable'", reinterpret_cast(g_pConCommandVFTable)); + LogConAdr("ConVar::`vbtable'", reinterpret_cast(g_pConVarVBTable)); + LogConAdr("ConVar::`vftable'", reinterpret_cast(g_pConVarVFTable)); + LogFunAdr("ConVar::Register", p_ConVar_Register.GetPtr()); + LogFunAdr("ConVar::Unregister", p_ConVar_Unregister.GetPtr()); + LogFunAdr("ConVar::IsFlagSet", p_ConVar_IsFlagSet.GetPtr()); + } + virtual void GetFun(void) const + { +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + p_ConVar_Register = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 F3 0F 10 44 24 ??"); + p_ConVar_Unregister = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 48 8B 59 58 48 8D 05 ?? ?? ?? ??"); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) + p_ConVar_Register = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 F3 0F 10 84 24 ?? ?? ?? ??"); + p_ConVar_Unregister = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B 79 58"); +#endif + p_ConVar_IsFlagSet = g_GameDll.FindPatternSIMD("48 8B 41 48 85 50 38"); + + v_ConVar_IsFlagSet = p_ConVar_IsFlagSet.RCast(); + v_ConVar_Register = p_ConVar_Register.RCast(); + v_ConVar_Unregister = p_ConVar_Unregister.RCast(); + } + virtual void GetVar(void) const { } + virtual void GetCon(void) const + { + g_pConCommandBaseVFTable = g_GameDll.GetVirtualMethodTable(".?AVConCommandBase@@").RCast(); + g_pConCommandVFTable = g_GameDll.GetVirtualMethodTable(".?AVConCommand@@").RCast(); + g_pConVarVBTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 0).RCast(); + g_pConVarVFTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 1).RCast(); + } + virtual void Attach(void) const { } + virtual void Detach(void) const { } +}; +/////////////////////////////////////////////////////////////////////////////// + +#endif // CONVAR_H diff --git a/r5dev/public/tier1/cvar.h b/r5dev/public/tier1/cvar.h index 79a05bf1..22d67a5e 100644 --- a/r5dev/public/tier1/cvar.h +++ b/r5dev/public/tier1/cvar.h @@ -13,11 +13,80 @@ #define CVAR_H #include "vstdlib/concommandhash.h" +#include "public/icvar.h" +#include "public/iconvar.h" #include "tier1/utlmap.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" -/* ==== CCVAR =========================================================================================================================================================== */ //----------------------------------------------------------------------------- -// Purpose: +// Forward declarations +//----------------------------------------------------------------------------- +class ConCommandBase; + +//----------------------------------------------------------------------------- +// Purpose: Interface to ConVars/ConCommands +//----------------------------------------------------------------------------- +class CCvar : public CBaseAppSystem< ICvar > +{ // Implementation in engine. +protected: + enum ConVarSetType_t + { + CONVAR_SET_STRING = 0, + CONVAR_SET_INT, + CONVAR_SET_FLOAT, + }; + + struct QueuedConVarSet_t + { + ConVar* m_pConVar; + ConVarSetType_t m_nType; + int m_nInt; + float m_flFloat; + CUtlString m_String; + }; + + class CCVarIteratorInternal : public ICVarIteratorInternal + { + public: + + virtual void SetFirst(void) = 0; + virtual void Next(void) = 0; + virtual bool IsValid(void) = 0; + virtual ConCommandBase* Get(void) = 0; + + virtual ~CCVarIteratorInternal() { } + + CCvar* const m_pOuter = nullptr; + CConCommandHash* const m_pHash = nullptr; + CConCommandHash::CCommandHashIterator_t m_hashIter; + }; + + virtual CCVarIteratorInternal* FactoryInternalIterator(void) = 0; + + friend class CCVarIteratorInternal; + friend class CCvarUtilities; + +private: + CUtlVector< FnChangeCallback_t > m_GlobalChangeCallbacks; + char pad0[30]; //!TODO: + int m_nNextDLLIdentifier; + ConCommandBase* m_pConCommandList; + CConCommandHash m_CommandHash; + CUtlVector m_Unknown; + char pad2[32]; + void* m_pCallbackStub; + void* m_pAllocFunc; + char pad3[16]; + CUtlVector< QueuedConVarSet_t > m_QueuedConVarSets; + bool m_bMaterialSystemThreadSetAllowed; +}; + +extern CCvar* g_pCVar; +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// Purpose: ConVar tools //----------------------------------------------------------------------------- class CCvarUtilities { @@ -63,204 +132,7 @@ private: }; extern CCvarUtilities* cv; - -class CCvar : public CBaseAppSystem< ICvar > -{ // Implementation in engine. -protected: - enum ConVarSetType_t - { - CONVAR_SET_STRING = 0, - CONVAR_SET_INT, - CONVAR_SET_FLOAT, - }; - - struct QueuedConVarSet_t - { - ConVar* m_pConVar; - ConVarSetType_t m_nType; - int m_nInt; - float m_flFloat; - CUtlString m_String; - }; - - class CCVarIteratorInternal : public ICVarIteratorInternal - { - public: - - virtual void SetFirst(void) = 0; - virtual void Next(void) = 0; - virtual bool IsValid(void) = 0; - virtual ConCommandBase* Get(void) = 0; - - virtual ~CCVarIteratorInternal() { } - - CCvar* const m_pOuter = nullptr; - CConCommandHash* const m_pHash = nullptr; - CConCommandHash::CCommandHashIterator_t m_hashIter; - }; - - virtual CCVarIteratorInternal* FactoryInternalIterator(void) = 0; - - friend class CCVarIteratorInternal; - friend class CCvarUtilities; - -private: - CUtlVector< FnChangeCallback_t > m_GlobalChangeCallbacks; - char pad0[30]; //!TODO: - int m_nNextDLLIdentifier; - ConCommandBase* m_pConCommandList; - CConCommandHash m_CommandHash; - CUtlVector m_Unknown; - char pad2[32]; - void* m_pCallbackStub; - void* m_pAllocFunc; - char pad3[16]; - CUtlVector< QueuedConVarSet_t > m_QueuedConVarSets; - bool m_bMaterialSystemThreadSetAllowed; -}; - /////////////////////////////////////////////////////////////////////////////// -extern CCvar* g_pCVar; - -/* ==== CONVAR ========================================================================================================================================================== */ -//----------------------------------------------------------------------------- -// Purpose: A console variable -//----------------------------------------------------------------------------- -class ConVar : public ConCommandBase, public IConVar -{ - friend class CCvar; - friend class ConVarRef; - -public: - static ConVar* StaticCreate(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, - bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); - void Destroy(void); - - ConVar(void); - virtual ~ConVar(void) { }; - - FORCEINLINE bool GetBool(void) const; - FORCEINLINE float GetFloat(void) const; - FORCEINLINE double GetDouble(void) const; - FORCEINLINE int GetInt(void) const; - FORCEINLINE Color GetColor(void) const; - FORCEINLINE const char* GetString(void) const; - - void SetMax(float flMaxValue); - void SetMin(float flMinValue); - bool GetMin(float& flMinValue) const; - bool GetMax(float& flMaxValue) const; - float GetMinValue(void) const; - float GetMaxValue(void) const; - bool HasMin(void) const; - bool HasMax(void) const; - - void SetValue(int nValue); - void SetValue(float flValue); - void SetValue(const char* pszValue); - void SetValue(Color clValue); - - virtual void InternalSetValue(const char* pszValue) = 0; - virtual void InternalSetFloatValue(float flValue) = 0; - virtual void InternalSetIntValue(int nValue) = 0; - void InternalSetColorValue(Color value); - - virtual __int64 Unknown0(unsigned int a2) = 0; - virtual __int64 Unknown1(const char* a2) = 0; - - void Revert(void); - virtual bool ClampValue(float& flValue) = 0; - - const char* GetDefault(void) const; - void SetDefault(const char* pszDefault); - bool SetColorFromString(const char* pszValue); - - virtual void ChangeStringValue(const char* pszTempValue) = 0; - virtual void CreateInternal(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, - bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString) = 0; - - void InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke); - void RemoveChangeCallback(FnChangeCallback_t callback); - - struct CVValue_t - { - char* m_pszString; - size_t m_iStringLength; - float m_fValue; - int m_nValue; - }; - - ConVar* m_pParent; //0x0048 - const char* m_pszDefaultValue; //0x0050 - CVValue_t m_Value; //0c0058 - bool m_bHasMin; //0x0070 - float m_fMinVal; //0x0074 - bool m_bHasMax; //0x0078 - float m_fMaxVal; //0x007C - CUtlVector m_fnChangeCallbacks; //0x0080 -}; //Size: 0x00A0 -static_assert(sizeof(ConVar) == 0xA0); - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a boolean. -// Output : bool -//----------------------------------------------------------------------------- -FORCEINLINE bool ConVar::GetBool(void) const -{ - return !!GetInt(); -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a float. -// Output : float -//----------------------------------------------------------------------------- -FORCEINLINE float ConVar::GetFloat(void) const -{ - return m_pParent->m_Value.m_fValue; -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a double. -// Output : double -//----------------------------------------------------------------------------- -FORCEINLINE double ConVar::GetDouble(void) const -{ - return static_cast(m_pParent->m_Value.m_fValue); -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as an integer. -// Output : int -//----------------------------------------------------------------------------- -FORCEINLINE int ConVar::GetInt(void) const -{ - return m_pParent->m_Value.m_nValue; -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a color. -// Output : Color -//----------------------------------------------------------------------------- -FORCEINLINE Color ConVar::GetColor(void) const -{ - unsigned char* pColorElement = (reinterpret_cast(&m_pParent->m_Value.m_nValue)); - return Color(pColorElement[0], pColorElement[1], pColorElement[2], pColorElement[3]); -} - -//----------------------------------------------------------------------------- -// Purpose: Return ConVar value as a string. -// Output : const char * -//----------------------------------------------------------------------------- -FORCEINLINE const char* ConVar::GetString(void) const -{ - if (m_nFlags & FCVAR_NEVER_AS_STRING) - { - return "FCVAR_NEVER_AS_STRING"; - } - - char const* str = m_pParent->m_Value.m_pszString; - return str ? str : ""; -} //----------------------------------------------------------------------------- // Purpose: Console variable flags container for tools @@ -289,52 +161,21 @@ extern ConVarFlags g_ConVarFlags; bool ConVar_ParseFlagString(const char* pszFlags, int& nFlags, const char* pszConVarName = "<>"); void ConVar_PrintDescription(ConCommandBase* pVar); -/* ==== CONVAR ========================================================================================================================================================== */ -inline CMemory p_ConVar_Register; -inline void*(*v_ConVar_Register)(ConVar* thisptr, const char* szName, const char* szDefaultValue, int nFlags, const char* szHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); - -inline CMemory p_ConVar_Unregister; -inline void(*v_ConVar_Unregister)(ConVar* thisptr); - -inline CMemory p_ConVar_IsFlagSet; -inline bool(*v_ConVar_IsFlagSet)(ConVar* pConVar, int nFlag); - inline CMemory p_ConVar_PrintDescription; -inline void*(*v_ConVar_PrintDescription)(ConCommandBase* pVar); - -inline ConVar* g_pConVarVBTable; -inline IConVar* g_pConVarVFTable; +inline void* (*v_ConVar_PrintDescription)(ConCommandBase* pVar); /////////////////////////////////////////////////////////////////////////////// class VCVar : public IDetour { virtual void GetAdr(void) const { - LogConAdr("ConCommand::`vftable'", reinterpret_cast(g_pConCommandVFTable)); - LogConAdr("ConVar::`vbtable'", reinterpret_cast(g_pConVarVBTable)); - LogConAdr("ConVar::`vftable'", reinterpret_cast(g_pConVarVFTable)); - LogFunAdr("ConVar::Register", p_ConVar_Register.GetPtr()); - LogFunAdr("ConVar::Unregister", p_ConVar_Unregister.GetPtr()); - LogFunAdr("ConVar::IsFlagSet", p_ConVar_IsFlagSet.GetPtr()); LogFunAdr("ConVar_PrintDescription", p_ConVar_PrintDescription.GetPtr()); LogVarAdr("g_pCVar", reinterpret_cast(g_pCVar)); } - virtual void GetFun(void) const + virtual void GetFun(void) const { -#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) - p_ConVar_Register = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 F3 0F 10 44 24 ??"); - p_ConVar_Unregister = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 48 8B 59 58 48 8D 05 ?? ?? ?? ??"); -#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) - p_ConVar_Register = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 F3 0F 10 84 24 ?? ?? ?? ??"); - p_ConVar_Unregister = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B 79 58"); -#endif - p_ConVar_IsFlagSet = g_GameDll.FindPatternSIMD("48 8B 41 48 85 50 38"); - p_ConVar_PrintDescription = g_GameDll.FindPatternSIMD("B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 01 48 89 9C 24 ?? ?? ?? ??"); - - v_ConVar_IsFlagSet = p_ConVar_IsFlagSet.RCast(); - v_ConVar_Register = p_ConVar_Register.RCast(); - v_ConVar_Unregister = p_ConVar_Unregister.RCast(); - v_ConVar_PrintDescription = p_ConVar_PrintDescription.RCast(); + p_ConVar_PrintDescription = g_GameDll.FindPatternSIMD("B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 01 48 89 9C 24 ?? ?? ?? ??"); + v_ConVar_PrintDescription = p_ConVar_PrintDescription.RCast(); } virtual void GetVar(void) const { @@ -344,11 +185,7 @@ class VCVar : public IDetour //g_pCVar = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 83 3D ?? ?? ?? ?? ?? 48 8B D9 74 09") // Actual CCvar, above is the vtable ptr. //.FindPatternSelf("48 83 3D", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x8).RCast(); } - virtual void GetCon(void) const - { - g_pConVarVBTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 0).RCast(); - g_pConVarVFTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 1).RCast(); - } + virtual void GetCon(void) const { } virtual void Attach(void) const; virtual void Detach(void) const; }; diff --git a/r5dev/tier1/CMakeLists.txt b/r5dev/tier1/CMakeLists.txt index 11ff85b3..d10a8eb0 100644 --- a/r5dev/tier1/CMakeLists.txt +++ b/r5dev/tier1/CMakeLists.txt @@ -22,6 +22,7 @@ add_sources( SOURCE_GROUP "Utility" add_sources( SOURCE_GROUP "Private" "cmd.cpp" + "convar.cpp" "cvar.cpp" ) diff --git a/r5dev/tier1/cmd.cpp b/r5dev/tier1/cmd.cpp index 1f82e861..da7349ce 100644 --- a/r5dev/tier1/cmd.cpp +++ b/r5dev/tier1/cmd.cpp @@ -274,90 +274,3 @@ void CCommand::Reset() m_pArgSBuffer[0] = 0; m_nQueuedVal = cmd_source_t::kCommandSrcInvalid; } - -//----------------------------------------------------------------------------- -// Purpose: create -//----------------------------------------------------------------------------- -ConCommand* ConCommand::StaticCreate(const char* pszName, const char* pszHelpString, const char* pszUsageString, - int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCompletionFunc) -{ - ConCommand* pCommand = (ConCommand*)malloc(sizeof(ConCommand)); - *(ConCommandBase**)pCommand = g_pConCommandVFTable; - - pCommand->m_pNext = nullptr; - pCommand->m_bRegistered = false; - - pCommand->m_pszName = pszName; - pCommand->m_pszHelpString = pszHelpString; - pCommand->m_pszUsageString = pszUsageString; - pCommand->s_pAccessor = nullptr; - pCommand->m_nFlags = nFlags; - - pCommand->m_nNullCallBack = NullSub; - pCommand->m_pSubCallback = nullptr; - pCommand->m_fnCommandCallback = pCallback; - pCommand->m_bHasCompletionCallback = pCompletionFunc != nullptr ? true : false; - pCommand->m_bUsingNewCommandCallback = true; - pCommand->m_bUsingCommandCallbackInterface = false; - pCommand->m_fnCompletionCallback = pCompletionFunc ? pCompletionFunc : CallbackStub; - - g_pCVar->RegisterConCommand(pCommand); - return pCommand; -} - -//----------------------------------------------------------------------------- -// Purpose: construct/allocate -//----------------------------------------------------------------------------- -ConCommand::ConCommand() - : m_nNullCallBack(nullptr) - , m_pSubCallback(nullptr) - , m_fnCommandCallbackV1(nullptr) - , m_fnCompletionCallback(nullptr) - , m_bHasCompletionCallback(false) - , m_bUsingNewCommandCallback(false) - , m_bUsingCommandCallbackInterface(false) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Checks if ConCommand has requested flags. -// Input : nFlags - -// Output : True if ConCommand has nFlags. -//----------------------------------------------------------------------------- -bool ConCommandBase::HasFlags(int nFlags) const -{ - return m_nFlags & nFlags; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : const ConCommandBase -//----------------------------------------------------------------------------- -ConCommandBase* ConCommandBase::GetNext(void) const -{ - return m_pNext; -} - -//----------------------------------------------------------------------------- -// Purpose: Copies string using local new/delete operators -// Input : *szFrom - -// Output : char -//----------------------------------------------------------------------------- -char* ConCommandBase::CopyString(const char* szFrom) const -{ - size_t nLen; - char* szTo; - - nLen = strlen(szFrom); - if (nLen <= 0) - { - szTo = new char[1]; - szTo[0] = 0; - } - else - { - szTo = new char[nLen + 1]; - memmove(szTo, szFrom, nLen + 1); - } - return szTo; -} diff --git a/r5dev/tier1/convar.cpp b/r5dev/tier1/convar.cpp new file mode 100644 index 00000000..c1c4a71c --- /dev/null +++ b/r5dev/tier1/convar.cpp @@ -0,0 +1,497 @@ +//=============================================================================// +// +// Purpose: +// +//=============================================================================// +#include "tier0/tslist.h" +#include "tier1/convar.h" + +//----------------------------------------------------------------------------- +// Purpose: Checks if ConCommand has requested flags. +// Input : nFlags - +// Output : True if ConCommand has nFlags. +//----------------------------------------------------------------------------- +bool ConCommandBase::HasFlags(int nFlags) const +{ + return m_nFlags & nFlags; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const ConCommandBase +//----------------------------------------------------------------------------- +ConCommandBase* ConCommandBase::GetNext(void) const +{ + return m_pNext; +} + +//----------------------------------------------------------------------------- +// Purpose: Copies string using local new/delete operators +// Input : *szFrom - +// Output : char +//----------------------------------------------------------------------------- +char* ConCommandBase::CopyString(const char* szFrom) const +{ + size_t nLen; + char* szTo; + + nLen = strlen(szFrom); + if (nLen <= 0) + { + szTo = new char[1]; + szTo[0] = 0; + } + else + { + szTo = new char[nLen + 1]; + memmove(szTo, szFrom, nLen + 1); + } + return szTo; +} + +//----------------------------------------------------------------------------- +// Default do nothing function +//----------------------------------------------------------------------------- +void DefaultNullSub() +{ + ; /*DO NOTHING*/ +} + +//----------------------------------------------------------------------------- +// Default console command autocompletion function +//----------------------------------------------------------------------------- +int DefaultCompletionFunc(const char* partial, char commands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH]) +{ + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: create +//----------------------------------------------------------------------------- +ConCommand* ConCommand::StaticCreate(const char* pszName, const char* pszHelpString, const char* pszUsageString, + int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCompletionFunc) +{ + ConCommand* pCommand = (ConCommand*)malloc(sizeof(ConCommand)); + *(ConCommand**)pCommand = g_pConCommandVFTable; + + pCommand->m_pNext = nullptr; + pCommand->m_bRegistered = false; + + pCommand->m_pszName = pszName; + pCommand->m_pszHelpString = pszHelpString; + pCommand->m_pszUsageString = pszUsageString; + pCommand->s_pAccessor = nullptr; + pCommand->m_nFlags = nFlags; + + pCommand->m_nNullCallBack = DefaultNullSub; + pCommand->m_pSubCallback = nullptr; + pCommand->m_fnCommandCallback = pCallback; + pCommand->m_bHasCompletionCallback = pCompletionFunc != nullptr ? true : false; + pCommand->m_bUsingNewCommandCallback = true; + pCommand->m_bUsingCommandCallbackInterface = false; + pCommand->m_fnCompletionCallback = pCompletionFunc ? pCompletionFunc : DefaultCompletionFunc; + + g_pCVar->RegisterConCommand(pCommand); + return pCommand; +} + +//----------------------------------------------------------------------------- +// Purpose: construct/allocate +//----------------------------------------------------------------------------- +ConCommand::ConCommand() + : m_nNullCallBack(nullptr) + , m_pSubCallback(nullptr) + , m_fnCommandCallbackV1(nullptr) + , m_fnCompletionCallback(nullptr) + , m_bHasCompletionCallback(false) + , m_bUsingNewCommandCallback(false) + , m_bUsingCommandCallbackInterface(false) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: create +//----------------------------------------------------------------------------- +ConVar* ConVar::StaticCreate(const char* pszName, const char* pszDefaultValue, + int nFlags, const char* pszHelpString, bool bMin, float fMin, bool bMax, + float fMax, FnChangeCallback_t pCallback, const char* pszUsageString) +{ + ConVar* pNewConVar = (ConVar*)malloc(sizeof(ConVar)); + + pNewConVar->m_bRegistered = false; + *(ConVar**)pNewConVar = g_pConVarVBTable; + char* pConVarVFTable = (char*)pNewConVar + sizeof(ConCommandBase); + *(IConVar**)pConVarVFTable = g_pConVarVFTable; + + pNewConVar->m_pszName = nullptr; + pNewConVar->m_pszHelpString = nullptr; + pNewConVar->m_pszUsageString = nullptr; + pNewConVar->s_pAccessor = nullptr; + pNewConVar->m_nFlags = FCVAR_NONE; + pNewConVar->m_pNext = nullptr; + + pNewConVar->m_fnChangeCallbacks.Init(); + + v_ConVar_Register(pNewConVar, pszName, pszDefaultValue, nFlags, + pszHelpString, bMin, fMin, bMax, fMax, pCallback, pszUsageString); + return pNewConVar; +} + +//----------------------------------------------------------------------------- +// Purpose: destroy +//----------------------------------------------------------------------------- +void ConVar::Destroy(void) +{ + v_ConVar_Unregister(this); +} + +//----------------------------------------------------------------------------- +// Purpose: construct/allocate +//----------------------------------------------------------------------------- +ConVar::ConVar(void) + : m_pParent(nullptr) + , m_pszDefaultValue(nullptr) + , m_bHasMin(false) + , m_fMinVal(0.f) + , m_bHasMax(false) + , m_fMaxVal(0.f) +{ + m_Value.m_pszString = nullptr; + m_Value.m_iStringLength = 0; + m_Value.m_fValue = 0.0f; + m_Value.m_nValue = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: destructor +//----------------------------------------------------------------------------- +//ConVar::~ConVar(void) +//{ +// if (m_Value.m_pszString) +// { +// delete[] m_Value.m_pszString); +// m_Value.m_pszString = NULL; +// } +//} + +////----------------------------------------------------------------------------- +//// Purpose: Returns the base ConVar name. +//// Output : const char* +////----------------------------------------------------------------------------- +//const char* ConVar::GetBaseName(void) const +//{ +// return m_pParent->m_pszName; +//} +// +////----------------------------------------------------------------------------- +//// Purpose: Returns the ConVar help text. +//// Output : const char* +////----------------------------------------------------------------------------- +//const char* ConVar::GetHelpText(void) const +//{ +// return m_pParent->m_pszHelpString; +//} +// +////----------------------------------------------------------------------------- +//// Purpose: Returns the ConVar usage text. +//// Output : const char* +////----------------------------------------------------------------------------- +//const char* ConVar::GetUsageText(void) const +//{ +// return m_pParent->m_pszUsageString; +//} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMaxVal - +//----------------------------------------------------------------------------- +void ConVar::SetMax(float flMaxVal) +{ + m_pParent->m_fMaxVal = flMaxVal; + m_pParent->m_bHasMax = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMinVal - +//----------------------------------------------------------------------------- +void ConVar::SetMin(float flMinVal) +{ + m_pParent->m_fMinVal = flMinVal; + m_pParent->m_bHasMin = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMinVal - +// Output : true if there is a min set. +//----------------------------------------------------------------------------- +bool ConVar::GetMin(float& flMinVal) const +{ + flMinVal = m_pParent->m_fMinVal; + return m_pParent->m_bHasMin; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMaxVal - +// Output : true if there is a max set. +//----------------------------------------------------------------------------- +bool ConVar::GetMax(float& flMaxVal) const +{ + flMaxVal = m_pParent->m_fMaxVal; + return m_pParent->m_bHasMax; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the min value. +// Output : float +//----------------------------------------------------------------------------- +float ConVar::GetMinValue(void) const +{ + return m_pParent->m_fMinVal; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the max value. +// Output : float +//----------------------------------------------------------------------------- +float ConVar::GetMaxValue(void) const +{ + return m_pParent->m_fMaxVal; +} + +//----------------------------------------------------------------------------- +// Purpose: checks if ConVar has min value. +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::HasMin(void) const +{ + return m_pParent->m_bHasMin; +} + +//----------------------------------------------------------------------------- +// Purpose: checks if ConVar has max value. +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::HasMax(void) const +{ + return m_pParent->m_bHasMax; +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar int value. +// Input : nValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(int nValue) +{ + ConVar* pCVar = reinterpret_cast(m_pParent); + pCVar->InternalSetIntValue(nValue); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar float value. +// Input : flValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(float flValue) +{ + ConVar* pCVar = reinterpret_cast(m_pParent); + pCVar->InternalSetFloatValue(flValue); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar string value. +// Input : *szValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(const char* pszValue) +{ + ConVar* pCVar = reinterpret_cast(m_pParent); + pCVar->InternalSetValue(pszValue); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar color value. +// Input : value - +//----------------------------------------------------------------------------- +void ConVar::SetValue(Color value) +{ + ConVar* pCVar = reinterpret_cast(m_pParent); + pCVar->InternalSetColorValue(value); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *value - +//----------------------------------------------------------------------------- +void ConVar::InternalSetColorValue(Color value) +{ + // Stuff color values into an int + int nValue = 0; + + unsigned char* pColorElement = (reinterpret_cast(&nValue)); + pColorElement[0] = value[0]; + pColorElement[1] = value[1]; + pColorElement[2] = value[2]; + pColorElement[3] = value[3]; + + // Call the int internal set + InternalSetIntValue(nValue); +} + +//----------------------------------------------------------------------------- +// Purpose: Reset to default value. +//----------------------------------------------------------------------------- +void ConVar::Revert(void) +{ + SetValue(m_pszDefaultValue); +} + +//----------------------------------------------------------------------------- +// Purpose: returns the default ConVar value. +// Output : const char +//----------------------------------------------------------------------------- +const char* ConVar::GetDefault(void) const +{ + return m_pParent->m_pszDefaultValue; +} + +//----------------------------------------------------------------------------- +// Purpose: sets the default ConVar value. +// Input : *pszDefault - +//----------------------------------------------------------------------------- +void ConVar::SetDefault(const char* pszDefault) +{ + static const char* pszEmpty = ""; + m_pszDefaultValue = pszDefault ? pszDefault : pszEmpty; + assert(m_pszDefaultValue); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar color value from string. +// Input : *pszValue - +//----------------------------------------------------------------------------- +bool ConVar::SetColorFromString(const char* pszValue) +{ + bool bColor = false; + + // Try pulling RGBA color values out of the string. + int nRGBA[4]; + int nParamsRead = sscanf_s(pszValue, "%i %i %i %i", + &(nRGBA[0]), &(nRGBA[1]), &(nRGBA[2]), &(nRGBA[3])); + + if (nParamsRead >= 3) + { + // This is probably a color! + if (nParamsRead == 3) + { + // Assume they wanted full alpha. + nRGBA[3] = 255; + } + + if (nRGBA[0] >= 0 && nRGBA[0] <= 255 && + nRGBA[1] >= 0 && nRGBA[1] <= 255 && + nRGBA[2] >= 0 && nRGBA[2] <= 255 && + nRGBA[3] >= 0 && nRGBA[3] <= 255) + { + //printf("*** WOW! Found a color!! ***\n"); + + // This is definitely a color! + bColor = true; + + // Stuff all the values into each byte of our int. + unsigned char* pColorElement = + (reinterpret_cast(&m_Value.m_nValue)); + + pColorElement[0] = (unsigned char)nRGBA[0]; + pColorElement[1] = (unsigned char)nRGBA[1]; + pColorElement[2] = (unsigned char)nRGBA[2]; + pColorElement[3] = (unsigned char)nRGBA[3]; + + // Copy that value into our float. + m_Value.m_fValue = static_cast(m_Value.m_nValue); + } + } + + return bColor; +} + +//----------------------------------------------------------------------------- +// Purpose: changes the ConVar string value. +// Input : *pszTempVal - flOldValue +//----------------------------------------------------------------------------- +void ConVar::ChangeStringValue(const char* pszTempVal) +{ + Assert(!(m_nFlags & FCVAR_NEVER_AS_STRING)); + + char* pszOldValue = (char*)stackalloc(m_Value.m_iStringLength); + memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength); + + size_t len = strlen(pszTempVal) + 1; + + if (len > m_Value.m_iStringLength) + { + if (m_Value.m_pszString) + { + delete[] m_Value.m_pszString; + } + + m_Value.m_pszString = new char[len]; + m_Value.m_iStringLength = len; + } + + memcpy(reinterpret_cast(m_Value.m_pszString), pszTempVal, len); + + // Invoke any necessary callback function + for (int i = 0; i < m_fnChangeCallbacks.Count(); ++i) + { + m_fnChangeCallbacks[i](this, pszOldValue, NULL); + } + + if (g_pCVar) + { + g_pCVar->CallGlobalChangeCallbacks(this, pszOldValue); + } + + stackfree(pszOldValue); +} + +//----------------------------------------------------------------------------- +// Purpose: Install a change callback (there shouldn't already be one....) +// Input : callback - +// bInvoke - +//----------------------------------------------------------------------------- +void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke /*=true*/) +{ + if (!callback) + { + Warning(eDLL_T::COMMON, "%s: Called with NULL callback; ignoring!!!\n", + __FUNCTION__); + return; + } + + if (m_pParent->m_fnChangeCallbacks.Find(callback) + != m_pParent->m_fnChangeCallbacks.InvalidIndex()) + { + // Same ptr added twice, sigh... + Warning(eDLL_T::COMMON, "%s: Ignoring duplicate change callback!!!\n", + __FUNCTION__); + return; + } + + m_pParent->m_fnChangeCallbacks.AddToTail(callback); + + // Call it immediately to set the initial value... + if (bInvoke) + { + callback(this, m_Value.m_pszString, m_Value.m_fValue); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Install a change callback (there shouldn't already be one....) +// Input : callback - +//----------------------------------------------------------------------------- +void ConVar::RemoveChangeCallback(FnChangeCallback_t callback) +{ + m_pParent->m_fnChangeCallbacks.FindAndRemove(callback); +} diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index bf460161..266bd4dd 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -1,398 +1,12 @@ -#include "tier1/utlrbtree.h" -#include "tier1/utlmap.h" -#include "tier1/NetAdr.h" +//=============================================================================// +// +// Purpose: +// +//=============================================================================// +#include "mathlib/color.h" +#include "tier1/convar.h" #include "tier1/cvar.h" -#include "public/const.h" -#include "engine/sys_dll2.h" #include "filesystem/filesystem.h" -#include "vstdlib/concommandhash.h" - -//----------------------------------------------------------------------------- -// Purpose: create -//----------------------------------------------------------------------------- -ConVar* ConVar::StaticCreate(const char* pszName, const char* pszDefaultValue, - int nFlags, const char* pszHelpString, bool bMin, float fMin, bool bMax, - float fMax, FnChangeCallback_t pCallback, const char* pszUsageString) -{ - ConVar* pNewConVar = (ConVar*)malloc(sizeof(ConVar)); - - pNewConVar->m_bRegistered = false; - *(ConVar**)pNewConVar = g_pConVarVBTable; - char* pConVarVFTable = (char*)pNewConVar + sizeof(ConCommandBase); - *(IConVar**)pConVarVFTable = g_pConVarVFTable; - - pNewConVar->m_pszName = nullptr; - pNewConVar->m_pszHelpString = nullptr; - pNewConVar->m_pszUsageString = nullptr; - pNewConVar->s_pAccessor = nullptr; - pNewConVar->m_nFlags = FCVAR_NONE; - pNewConVar->m_pNext = nullptr; - - pNewConVar->m_fnChangeCallbacks.Init(); - - v_ConVar_Register(pNewConVar, pszName, pszDefaultValue, nFlags, - pszHelpString, bMin, fMin, bMax, fMax, pCallback, pszUsageString); - return pNewConVar; -} - -//----------------------------------------------------------------------------- -// Purpose: destroy -//----------------------------------------------------------------------------- -void ConVar::Destroy(void) -{ - v_ConVar_Unregister(this); -} - -//----------------------------------------------------------------------------- -// Purpose: construct/allocate -//----------------------------------------------------------------------------- -ConVar::ConVar(void) - : m_pParent(nullptr) - , m_pszDefaultValue(nullptr) - , m_bHasMin(false) - , m_fMinVal(0.f) - , m_bHasMax(false) - , m_fMaxVal(0.f) -{ - m_Value.m_pszString = nullptr; - m_Value.m_iStringLength = 0; - m_Value.m_fValue = 0.0f; - m_Value.m_nValue = 0; -} - -//----------------------------------------------------------------------------- -// Purpose: destructor -//----------------------------------------------------------------------------- -//ConVar::~ConVar(void) -//{ -// if (m_Value.m_pszString) -// { -// delete[] m_Value.m_pszString); -// m_Value.m_pszString = NULL; -// } -//} - -////----------------------------------------------------------------------------- -//// Purpose: Returns the base ConVar name. -//// Output : const char* -////----------------------------------------------------------------------------- -//const char* ConVar::GetBaseName(void) const -//{ -// return m_pParent->m_pszName; -//} -// -////----------------------------------------------------------------------------- -//// Purpose: Returns the ConVar help text. -//// Output : const char* -////----------------------------------------------------------------------------- -//const char* ConVar::GetHelpText(void) const -//{ -// return m_pParent->m_pszHelpString; -//} -// -////----------------------------------------------------------------------------- -//// Purpose: Returns the ConVar usage text. -//// Output : const char* -////----------------------------------------------------------------------------- -//const char* ConVar::GetUsageText(void) const -//{ -// return m_pParent->m_pszUsageString; -//} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flMaxVal - -//----------------------------------------------------------------------------- -void ConVar::SetMax(float flMaxVal) -{ - m_pParent->m_fMaxVal = flMaxVal; - m_pParent->m_bHasMax = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flMinVal - -//----------------------------------------------------------------------------- -void ConVar::SetMin(float flMinVal) -{ - m_pParent->m_fMinVal = flMinVal; - m_pParent->m_bHasMin = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flMinVal - -// Output : true if there is a min set. -//----------------------------------------------------------------------------- -bool ConVar::GetMin(float& flMinVal) const -{ - flMinVal = m_pParent->m_fMinVal; - return m_pParent->m_bHasMin; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : flMaxVal - -// Output : true if there is a max set. -//----------------------------------------------------------------------------- -bool ConVar::GetMax(float& flMaxVal) const -{ - flMaxVal = m_pParent->m_fMaxVal; - return m_pParent->m_bHasMax; -} - -//----------------------------------------------------------------------------- -// Purpose: returns the min value. -// Output : float -//----------------------------------------------------------------------------- -float ConVar::GetMinValue(void) const -{ - return m_pParent->m_fMinVal; -} - -//----------------------------------------------------------------------------- -// Purpose: returns the max value. -// Output : float -//----------------------------------------------------------------------------- -float ConVar::GetMaxValue(void) const -{ - return m_pParent->m_fMaxVal; -} - -//----------------------------------------------------------------------------- -// Purpose: checks if ConVar has min value. -// Output : bool -//----------------------------------------------------------------------------- -bool ConVar::HasMin(void) const -{ - return m_pParent->m_bHasMin; -} - -//----------------------------------------------------------------------------- -// Purpose: checks if ConVar has max value. -// Output : bool -//----------------------------------------------------------------------------- -bool ConVar::HasMax(void) const -{ - return m_pParent->m_bHasMax; -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar int value. -// Input : nValue - -//----------------------------------------------------------------------------- -void ConVar::SetValue(int nValue) -{ - ConVar* pCVar = reinterpret_cast(m_pParent); - pCVar->InternalSetIntValue(nValue); -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar float value. -// Input : flValue - -//----------------------------------------------------------------------------- -void ConVar::SetValue(float flValue) -{ - ConVar* pCVar = reinterpret_cast(m_pParent); - pCVar->InternalSetFloatValue(flValue); -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar string value. -// Input : *szValue - -//----------------------------------------------------------------------------- -void ConVar::SetValue(const char* pszValue) -{ - ConVar* pCVar = reinterpret_cast(m_pParent); - pCVar->InternalSetValue(pszValue); -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar color value. -// Input : value - -//----------------------------------------------------------------------------- -void ConVar::SetValue(Color value) -{ - ConVar* pCVar = reinterpret_cast(m_pParent); - pCVar->InternalSetColorValue(value); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *value - -//----------------------------------------------------------------------------- -void ConVar::InternalSetColorValue(Color value) -{ - // Stuff color values into an int - int nValue = 0; - - unsigned char* pColorElement = (reinterpret_cast(&nValue)); - pColorElement[0] = value[0]; - pColorElement[1] = value[1]; - pColorElement[2] = value[2]; - pColorElement[3] = value[3]; - - // Call the int internal set - InternalSetIntValue(nValue); -} - -//----------------------------------------------------------------------------- -// Purpose: Reset to default value. -//----------------------------------------------------------------------------- -void ConVar::Revert(void) -{ - SetValue(m_pszDefaultValue); -} - -//----------------------------------------------------------------------------- -// Purpose: returns the default ConVar value. -// Output : const char -//----------------------------------------------------------------------------- -const char* ConVar::GetDefault(void) const -{ - return m_pParent->m_pszDefaultValue; -} - -//----------------------------------------------------------------------------- -// Purpose: sets the default ConVar value. -// Input : *pszDefault - -//----------------------------------------------------------------------------- -void ConVar::SetDefault(const char* pszDefault) -{ - static const char* pszEmpty = ""; - m_pszDefaultValue = pszDefault ? pszDefault : pszEmpty; - assert(m_pszDefaultValue); -} - -//----------------------------------------------------------------------------- -// Purpose: sets the ConVar color value from string. -// Input : *pszValue - -//----------------------------------------------------------------------------- -bool ConVar::SetColorFromString(const char* pszValue) -{ - bool bColor = false; - - // Try pulling RGBA color values out of the string. - int nRGBA[4]; - int nParamsRead = sscanf_s(pszValue, "%i %i %i %i", - &(nRGBA[0]), &(nRGBA[1]), &(nRGBA[2]), &(nRGBA[3])); - - if (nParamsRead >= 3) - { - // This is probably a color! - if (nParamsRead == 3) - { - // Assume they wanted full alpha. - nRGBA[3] = 255; - } - - if (nRGBA[0] >= 0 && nRGBA[0] <= 255 && - nRGBA[1] >= 0 && nRGBA[1] <= 255 && - nRGBA[2] >= 0 && nRGBA[2] <= 255 && - nRGBA[3] >= 0 && nRGBA[3] <= 255) - { - //printf("*** WOW! Found a color!! ***\n"); - - // This is definitely a color! - bColor = true; - - // Stuff all the values into each byte of our int. - unsigned char* pColorElement = - (reinterpret_cast(&m_Value.m_nValue)); - - pColorElement[0] = (unsigned char)nRGBA[0]; - pColorElement[1] = (unsigned char)nRGBA[1]; - pColorElement[2] = (unsigned char)nRGBA[2]; - pColorElement[3] = (unsigned char)nRGBA[3]; - - // Copy that value into our float. - m_Value.m_fValue = static_cast(m_Value.m_nValue); - } - } - - return bColor; -} - -//----------------------------------------------------------------------------- -// Purpose: changes the ConVar string value. -// Input : *pszTempVal - flOldValue -//----------------------------------------------------------------------------- -void ConVar::ChangeStringValue(const char* pszTempVal) -{ - Assert(!(m_nFlags & FCVAR_NEVER_AS_STRING)); - - char* pszOldValue = (char*)stackalloc(m_Value.m_iStringLength); - memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength); - - size_t len = strlen(pszTempVal) + 1; - - if (len > m_Value.m_iStringLength) - { - if (m_Value.m_pszString) - { - delete[] m_Value.m_pszString; - } - - m_Value.m_pszString = new char[len]; - m_Value.m_iStringLength = len; - } - - memcpy(reinterpret_cast(m_Value.m_pszString), pszTempVal, len); - - // Invoke any necessary callback function - for (int i = 0; i < m_fnChangeCallbacks.Count(); ++i) - { - m_fnChangeCallbacks[i](this, pszOldValue, NULL); - } - - if (g_pCVar) - { - g_pCVar->CallGlobalChangeCallbacks(this, pszOldValue); - } - - stackfree(pszOldValue); -} - -//----------------------------------------------------------------------------- -// Purpose: Install a change callback (there shouldn't already be one....) -// Input : callback - -// bInvoke - -//----------------------------------------------------------------------------- -void ConVar::InstallChangeCallback(FnChangeCallback_t callback, bool bInvoke /*=true*/) -{ - if (!callback) - { - Warning(eDLL_T::COMMON, "%s: Called with NULL callback; ignoring!!!\n", - __FUNCTION__); - return; - } - - if (m_pParent->m_fnChangeCallbacks.Find(callback) - != m_pParent->m_fnChangeCallbacks.InvalidIndex()) - { - // Same ptr added twice, sigh... - Warning(eDLL_T::COMMON, "%s: Ignoring duplicate change callback!!!\n", - __FUNCTION__); - return; - } - - m_pParent->m_fnChangeCallbacks.AddToTail(callback); - - // Call it immediately to set the initial value... - if (bInvoke) - { - callback(this, m_Value.m_pszString, m_Value.m_fValue); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Install a change callback (there shouldn't already be one....) -// Input : callback - -//----------------------------------------------------------------------------- -void ConVar::RemoveChangeCallback(FnChangeCallback_t callback) -{ - m_pParent->m_fnChangeCallbacks.FindAndRemove(callback); -} #define SET_CONVARFLAG(x, y) SetFlag(FCVAR_##x, #x, y) //----------------------------------------------------------------------------- @@ -1064,212 +678,6 @@ int CCvarUtilities::CvarFindFlagsCompletionCallback(const char* partial, /////////////////////////////////////////////////////////////////////////////// CCvar* g_pCVar = nullptr; - -//----------------------------------------------------------------------------- -// Console command hash data structure -//----------------------------------------------------------------------------- -CConCommandHash::CConCommandHash() -{ - Purge(true); -} - -CConCommandHash::~CConCommandHash() -{ - Purge(false); -} - -void CConCommandHash::Purge(bool bReinitialize) -{ - m_aBuckets.Purge(); - m_aDataPool.Purge(); - if (bReinitialize) - { - Init(); - } -} - -// Initialize. -void CConCommandHash::Init(void) -{ - // kNUM_BUCKETS must be a power of two. - COMPILE_TIME_ASSERT((kNUM_BUCKETS & (kNUM_BUCKETS - 1)) == 0); - - // Set the bucket size. - m_aBuckets.SetSize(kNUM_BUCKETS); - for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket) - { - m_aBuckets[iBucket] = m_aDataPool.InvalidIndex(); - } - - // Calculate the grow size. - int nGrowSize = 4 * kNUM_BUCKETS; - m_aDataPool.SetGrowSize(nGrowSize); -} - -//----------------------------------------------------------------------------- -// Purpose: Insert data into the hash table given its key (unsigned int), -// WITH a check to see if the element already exists within the hash. -//----------------------------------------------------------------------------- -CConCommandHash::CCommandHashHandle_t CConCommandHash::Insert(ConCommandBase* cmd) -{ - // Check to see if that key already exists in the buckets (should be unique). - CCommandHashHandle_t hHash = Find(cmd); - if (hHash != InvalidHandle()) - return hHash; - - return FastInsert(cmd); -} -//----------------------------------------------------------------------------- -// Purpose: Insert data into the hash table given its key (unsigned int), -// WITHOUT a check to see if the element already exists within the hash. -//----------------------------------------------------------------------------- -CConCommandHash::CCommandHashHandle_t CConCommandHash::FastInsert(ConCommandBase* cmd) -{ - // Get a new element from the pool. - intptr_t iHashData = m_aDataPool.Alloc(true); - HashEntry_t* RESTRICT pHashData = &m_aDataPool[iHashData]; - if (!pHashData) - return InvalidHandle(); - - HashKey_t key = Hash(cmd); - - // Add data to new element. - pHashData->m_uiKey = key; - pHashData->m_Data = cmd; - - // Link element. - int iBucket = key & kBUCKETMASK; // HashFuncs::Hash( uiKey, m_uiBucketMask ); - m_aDataPool.LinkBefore(m_aBuckets[iBucket], iHashData); - m_aBuckets[iBucket] = iHashData; - - return iHashData; -} - -//----------------------------------------------------------------------------- -// Purpose: Remove a given element from the hash. -//----------------------------------------------------------------------------- -void CConCommandHash::Remove(CCommandHashHandle_t hHash) /*RESTRICT*/ -{ - HashEntry_t* /*RESTRICT*/ entry = &m_aDataPool[hHash]; - HashKey_t iBucket = entry->m_uiKey & kBUCKETMASK; - if (m_aBuckets[iBucket] == hHash) - { - // It is a bucket head. - m_aBuckets[iBucket] = m_aDataPool.Next(hHash); - } - else - { - // Not a bucket head. - m_aDataPool.Unlink(hHash); - } - - // Remove the element. - m_aDataPool.Remove(hHash); -} - -//----------------------------------------------------------------------------- -// Purpose: Remove all elements from the hash -//----------------------------------------------------------------------------- -void CConCommandHash::RemoveAll(void) -{ - m_aBuckets.RemoveAll(); - m_aDataPool.RemoveAll(); -} - -//----------------------------------------------------------------------------- -// Find hash entry corresponding to a string name -//----------------------------------------------------------------------------- -CConCommandHash::CCommandHashHandle_t CConCommandHash::Find( - const char* name, HashKey_t hashkey) const /*RESTRICT*/ -{ - // hash the "key" - get the correct hash table "bucket" - int iBucket = hashkey & kBUCKETMASK; - - for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; - iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) - { - const HashEntry_t& element = m_aDataPool[iElement]; - if (element.m_uiKey == hashkey && // if hashes of strings match, - Q_stricmp(name, element.m_Data->GetName()) == 0) // then test the actual strings - { - return iElement; - } - } - - // found nuffink - return InvalidHandle(); -} - -//----------------------------------------------------------------------------- -// Find a command in the hash. -//----------------------------------------------------------------------------- -CConCommandHash::CCommandHashHandle_t CConCommandHash::Find(const ConCommandBase* cmd) const /*RESTRICT*/ -{ - // Set this #if to 1 if the assert at bottom starts whining -- - // that indicates that a console command is being double-registered, - // or something similarly non-fatally bad. With this #if 1, we'll search - // by name instead of by pointer, which is more robust in the face - // of double registered commands, but obviously slower. -#if 0 - return Find(cmd->GetName()); -#else - HashKey_t hashkey = Hash(cmd); - int iBucket = hashkey & kBUCKETMASK; - - // hunt through all entries in that bucket - for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; - iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) - { - const HashEntry_t& element = m_aDataPool[iElement]; - if (element.m_uiKey == hashkey && // if the hashes match... - element.m_Data == cmd) // and the pointers... - { - // in debug, test to make sure we don't have commands under the same name - // or something goofy like that - Assert(iElement == Find(cmd->GetName()), - "ConCommand %s had two entries in the hash!", cmd->GetName()); - - // return this element - return iElement; - } - } - - // found nothing. -#ifdef DBGFLAG_ASSERT // double check against search by name - CCommandHashHandle_t dbghand = Find(cmd->GetName()); - - Assert(InvalidHandle() == dbghand, - "ConCommand %s couldn't be found by pointer, but was found by name!", cmd->GetName()); -#endif - return InvalidHandle(); -#endif -} - - -//#ifdef _DEBUG -// Dump a report to MSG -void CConCommandHash::Report(void) -{ - DevMsg(eDLL_T::COMMON, "Console command hash bucket load:\n"); - int total = 0; - for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket) - { - int count = 0; - CCommandHashHandle_t iElement = m_aBuckets[iBucket]; // get the head of the bucket - while (iElement != m_aDataPool.InvalidIndex()) - { - ++count; - iElement = m_aDataPool.Next(iElement); - } - - DevMsg(eDLL_T::COMMON, "%d: %d\n", iBucket, count); - total += count; - } - - DevMsg(eDLL_T::COMMON, "\tAverage: %.1f\n", total / ((float)(kNUM_BUCKETS))); -} -//#endif - /////////////////////////////////////////////////////////////////////////////// void VCVar::Attach() const { diff --git a/r5dev/vstdlib/CMakeLists.txt b/r5dev/vstdlib/CMakeLists.txt index 58b9dc5b..c6aa9c7c 100644 --- a/r5dev/vstdlib/CMakeLists.txt +++ b/r5dev/vstdlib/CMakeLists.txt @@ -6,6 +6,7 @@ start_sources() add_sources( SOURCE_GROUP "Private" "autocompletefilelist.cpp" "autocompletefilelist.h" + "concommandhash.cpp" "concommandhash.h" "keyvaluessystem.cpp" "keyvaluessystem.h" diff --git a/r5dev/vstdlib/concommandhash.cpp b/r5dev/vstdlib/concommandhash.cpp new file mode 100644 index 00000000..2fdd8009 --- /dev/null +++ b/r5dev/vstdlib/concommandhash.cpp @@ -0,0 +1,211 @@ +//=============================================================================// +// +// Purpose: +// +//=============================================================================// +#include "concommandhash.h" + +//----------------------------------------------------------------------------- +// Console command hash data structure +//----------------------------------------------------------------------------- +CConCommandHash::CConCommandHash() +{ + Purge(true); +} + +CConCommandHash::~CConCommandHash() +{ + Purge(false); +} + +void CConCommandHash::Purge(bool bReinitialize) +{ + m_aBuckets.Purge(); + m_aDataPool.Purge(); + if (bReinitialize) + { + Init(); + } +} + +// Initialize. +void CConCommandHash::Init(void) +{ + // kNUM_BUCKETS must be a power of two. + COMPILE_TIME_ASSERT((kNUM_BUCKETS & (kNUM_BUCKETS - 1)) == 0); + + // Set the bucket size. + m_aBuckets.SetSize(kNUM_BUCKETS); + for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket) + { + m_aBuckets[iBucket] = m_aDataPool.InvalidIndex(); + } + + // Calculate the grow size. + int nGrowSize = 4 * kNUM_BUCKETS; + m_aDataPool.SetGrowSize(nGrowSize); +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), +// WITH a check to see if the element already exists within the hash. +//----------------------------------------------------------------------------- +CConCommandHash::CCommandHashHandle_t CConCommandHash::Insert(ConCommandBase* cmd) +{ + // Check to see if that key already exists in the buckets (should be unique). + CCommandHashHandle_t hHash = Find(cmd); + if (hHash != InvalidHandle()) + return hHash; + + return FastInsert(cmd); +} +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), +// WITHOUT a check to see if the element already exists within the hash. +//----------------------------------------------------------------------------- +CConCommandHash::CCommandHashHandle_t CConCommandHash::FastInsert(ConCommandBase* cmd) +{ + // Get a new element from the pool. + intptr_t iHashData = m_aDataPool.Alloc(true); + HashEntry_t* RESTRICT pHashData = &m_aDataPool[iHashData]; + if (!pHashData) + return InvalidHandle(); + + HashKey_t key = Hash(cmd); + + // Add data to new element. + pHashData->m_uiKey = key; + pHashData->m_Data = cmd; + + // Link element. + int iBucket = key & kBUCKETMASK; // HashFuncs::Hash( uiKey, m_uiBucketMask ); + m_aDataPool.LinkBefore(m_aBuckets[iBucket], iHashData); + m_aBuckets[iBucket] = iHashData; + + return iHashData; +} + +//----------------------------------------------------------------------------- +// Purpose: Remove a given element from the hash. +//----------------------------------------------------------------------------- +void CConCommandHash::Remove(CCommandHashHandle_t hHash) /*RESTRICT*/ +{ + HashEntry_t* /*RESTRICT*/ entry = &m_aDataPool[hHash]; + HashKey_t iBucket = entry->m_uiKey & kBUCKETMASK; + if (m_aBuckets[iBucket] == hHash) + { + // It is a bucket head. + m_aBuckets[iBucket] = m_aDataPool.Next(hHash); + } + else + { + // Not a bucket head. + m_aDataPool.Unlink(hHash); + } + + // Remove the element. + m_aDataPool.Remove(hHash); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove all elements from the hash +//----------------------------------------------------------------------------- +void CConCommandHash::RemoveAll(void) +{ + m_aBuckets.RemoveAll(); + m_aDataPool.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Find hash entry corresponding to a string name +//----------------------------------------------------------------------------- +CConCommandHash::CCommandHashHandle_t CConCommandHash::Find( + const char* name, HashKey_t hashkey) const /*RESTRICT*/ +{ + // hash the "key" - get the correct hash table "bucket" + int iBucket = hashkey & kBUCKETMASK; + + for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; + iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) + { + const HashEntry_t& element = m_aDataPool[iElement]; + if (element.m_uiKey == hashkey && // if hashes of strings match, + Q_stricmp(name, element.m_Data->GetName()) == 0) // then test the actual strings + { + return iElement; + } + } + + // found nuffink + return InvalidHandle(); +} + +//----------------------------------------------------------------------------- +// Find a command in the hash. +//----------------------------------------------------------------------------- +CConCommandHash::CCommandHashHandle_t CConCommandHash::Find(const ConCommandBase* cmd) const /*RESTRICT*/ +{ + // Set this #if to 1 if the assert at bottom starts whining -- + // that indicates that a console command is being double-registered, + // or something similarly non-fatally bad. With this #if 1, we'll search + // by name instead of by pointer, which is more robust in the face + // of double registered commands, but obviously slower. +#if 0 + return Find(cmd->GetName()); +#else + HashKey_t hashkey = Hash(cmd); + int iBucket = hashkey & kBUCKETMASK; + + // hunt through all entries in that bucket + for (datapool_t::IndexLocalType_t iElement = m_aBuckets[iBucket]; + iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next(iElement)) + { + const HashEntry_t& element = m_aDataPool[iElement]; + if (element.m_uiKey == hashkey && // if the hashes match... + element.m_Data == cmd) // and the pointers... + { + // in debug, test to make sure we don't have commands under the same name + // or something goofy like that + Assert(iElement == Find(cmd->GetName()), + "ConCommand %s had two entries in the hash!", cmd->GetName()); + + // return this element + return iElement; + } + } + + // found nothing. +#ifdef DBGFLAG_ASSERT // double check against search by name + CCommandHashHandle_t dbghand = Find(cmd->GetName()); + + Assert(InvalidHandle() == dbghand, + "ConCommand %s couldn't be found by pointer, but was found by name!", cmd->GetName()); +#endif + return InvalidHandle(); +#endif +} + + +//#ifdef _DEBUG +// Dump a report to MSG +void CConCommandHash::Report(void) +{ + DevMsg(eDLL_T::COMMON, "Console command hash bucket load:\n"); + int total = 0; + for (int iBucket = 0; iBucket < kNUM_BUCKETS; ++iBucket) + { + int count = 0; + CCommandHashHandle_t iElement = m_aBuckets[iBucket]; // get the head of the bucket + while (iElement != m_aDataPool.InvalidIndex()) + { + ++count; + iElement = m_aDataPool.Next(iElement); + } + + DevMsg(eDLL_T::COMMON, "%d: %d\n", iBucket, count); + total += count; + } + + DevMsg(eDLL_T::COMMON, "\tAverage: %.1f\n", total / ((float)(kNUM_BUCKETS))); +} +//#endif \ No newline at end of file diff --git a/r5dev/vstdlib/concommandhash.h b/r5dev/vstdlib/concommandhash.h index cbcd5956..7da9d8a5 100644 --- a/r5dev/vstdlib/concommandhash.h +++ b/r5dev/vstdlib/concommandhash.h @@ -12,10 +12,10 @@ #pragma once #endif -#include "tier1/cmd.h" #include "tier1/utlvector.h" #include "tier1/utllinkedlist.h" #include "tier1/generichash.h" +#include "tier1/convar.h" // This is a hash table class very similar to the CUtlHashFast, but // modified specifically so that we can look up ConCommandBases From e7420a26af3c69ce6c699d2650d060e500aa3fd6 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:35:20 +0200 Subject: [PATCH 10/24] Properly tokenize netconsole input Use the command tokenizer class. --- r5dev/netconsole/netconsole.cpp | 57 ++++++++++++++++----------------- r5dev/netconsole/netconsole.h | 3 ++ 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index df019390..c178a7b8 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -26,6 +26,7 @@ CNetCon::CNetCon(void) , m_bPromptConnect(true) , m_flTickInterval(0.05f) { + CharacterSetBuild(&m_CharacterSet, ""); } //----------------------------------------------------------------------------- @@ -122,31 +123,33 @@ void CNetCon::UserInput(void) } std::lock_guard l(m_Mutex); + if (IsConnected()) { - if (m_Input.compare("disconnect") == 0) + CCommand cmd; + cmd.Tokenize(m_Input.c_str()); + + if (V_strcmp(cmd.Arg(0), "disconnect") == 0) { Disconnect("user closed connection"); return; } - // !TODO[ AMOS ]: Swap out with CCommand! - const vector vSubStrings = StringSplit(m_Input, ' ', 2); vector vecMsg; const SocketHandle_t hSocket = GetSocket(); bool bSend = false; - if (vSubStrings.size() > 1) + if (cmd.ArgC() > 1) { - if (vSubStrings[0].compare("PASS") == 0) // Auth with RCON server. + if (V_strcmp(cmd.Arg(0), "PASS") == 0) // Auth with RCON server. { - bSend = Serialize(vecMsg, vSubStrings[1].c_str(), "", + bSend = Serialize(vecMsg, cmd.Arg(1), "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); } else // Execute command query. { - bSend = Serialize(vecMsg, m_Input.c_str(), "", + bSend = Serialize(vecMsg, cmd.Arg(0), cmd.GetCommandString(), cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); } } @@ -165,34 +168,30 @@ void CNetCon::UserInput(void) } else // Setup connection from input. { - const vector vSubStrings = StringSplit(m_Input, ' ', 2); - if (vSubStrings.size() > 1) + CCommand cmd; + cmd.Tokenize(m_Input.c_str(), cmd_source_t::kCommandSrcCode, &m_CharacterSet); + + if (cmd.ArgC() > 1) { - const string::size_type nPos = m_Input.find(' '); - if (nPos > 0 - && nPos < m_Input.size() - && nPos != m_Input.size()) + const char* inAddr = cmd.Arg(0); + const char* inPort = cmd.Arg(1); + + if (!*inAddr || !*inPort) { - string svInPort = m_Input.substr(nPos + 1); - string svInAdr = m_Input.erase(m_Input.find(' ')); + Warning(eDLL_T::CLIENT, "No IP address or port provided\n"); + m_bPromptConnect = true; + return; + } - if (svInPort.empty() || svInAdr.empty()) - { - Warning(eDLL_T::CLIENT, "No IP address or port provided\n"); - m_bPromptConnect = true; - return; - } - - if (!Connect(svInAdr.c_str(), atoi(svInPort.c_str()))) - { - m_bPromptConnect = true; - return; - } + if (!Connect(inAddr, atoi(inPort))) + { + m_bPromptConnect = true; + return; } } - else // Initialize as [ip]:port. + else { - if (m_Input.empty() || !Connect(m_Input.c_str())) + if (!Connect(cmd.GetCommandString())) { m_bPromptConnect = true; return; diff --git a/r5dev/netconsole/netconsole.h b/r5dev/netconsole/netconsole.h index 45a1bb01..a4a1a96e 100644 --- a/r5dev/netconsole/netconsole.h +++ b/r5dev/netconsole/netconsole.h @@ -4,6 +4,7 @@ // //===========================================================================// #pragma once +#include "tier1/cmd.h" #include "protoc/cl_rcon.pb.h" #include "protoc/sv_rcon.pb.h" #include "engine/shared/base_rcon.h" @@ -42,6 +43,8 @@ private: bool m_bPromptConnect; float m_flTickInterval; + characterset_t m_CharacterSet; + std::string m_Input; mutable std::mutex m_Mutex; }; From 461fb48575dcacdddc8273e4735a5f3fc5775ac4 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:36:40 +0200 Subject: [PATCH 11/24] More reliable way of enablin ansi colors on netconsole Compare arguments individually instead of performing a scan over the whole command line string. --- r5dev/netconsole/netconsole.cpp | 26 +++++++++++++++++--------- r5dev/netconsole/netconsole.h | 4 ++-- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index c178a7b8..e452f162 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -40,7 +40,7 @@ CNetCon::~CNetCon(void) // Purpose: WSA and NETCON systems init // Output : true on success, false otherwise //----------------------------------------------------------------------------- -bool CNetCon::Init(void) +bool CNetCon::Init(const bool bAnsiColor) { g_CoreMsgVCallback = &EngineLoggerSink; @@ -55,7 +55,7 @@ bool CNetCon::Init(void) m_bInitialized = true; - TermSetup(); + TermSetup(bAnsiColor); DevMsg(eDLL_T::NONE, "R5 TCP net console [Version %s]\n", NETCON_VERSION); static std::thread frame([this]() @@ -100,13 +100,10 @@ bool CNetCon::Shutdown(void) //----------------------------------------------------------------------------- // Purpose: terminal setup //----------------------------------------------------------------------------- -void CNetCon::TermSetup(void) +void CNetCon::TermSetup(const bool bAnsiColor) { - const char* pszCommandLine = GetCommandLineA(); - const bool bEnableColor = strstr("-ansicolor", pszCommandLine) != nullptr; - - SpdLog_Init(bEnableColor); - Console_Init(bEnableColor); + SpdLog_Init(bAnsiColor); + Console_Init(bAnsiColor); } //----------------------------------------------------------------------------- @@ -360,7 +357,18 @@ bool CNetCon::IsConnected(void) //----------------------------------------------------------------------------- int main(int argc, char* argv[]) { - if (!NetConsole()->Init()) + bool bEnableColor = false; + + for (int i = 0; i < argc; i++) + { + if (V_strcmp(argv[i], "-ansicolor") == NULL) + { + bEnableColor = true; + break; + } + } + + if (!NetConsole()->Init(bEnableColor)) { return EXIT_FAILURE; } diff --git a/r5dev/netconsole/netconsole.h b/r5dev/netconsole/netconsole.h index a4a1a96e..2a0926a6 100644 --- a/r5dev/netconsole/netconsole.h +++ b/r5dev/netconsole/netconsole.h @@ -17,10 +17,10 @@ public: CNetCon(void); ~CNetCon(void); - bool Init(void); + bool Init(const bool bAnsiColor); bool Shutdown(void); - void TermSetup(void); + void TermSetup(const bool bAnsiColor); void UserInput(void); void ClearInput(void); From 3a19ac0c24deb6f18cea34a2db1ebf4a2b71bb2f Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:39:40 +0200 Subject: [PATCH 12/24] Add a note --- r5dev/netconsole/netconsole.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index e452f162..1736932d 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -26,6 +26,9 @@ CNetCon::CNetCon(void) , m_bPromptConnect(true) , m_flTickInterval(0.05f) { + // Empty character set used for ip addresses if we still need to initiate a + // connection, as we don't want to break on ':' characters found in an IPv6 + // address. CharacterSetBuild(&m_CharacterSet, ""); } From f2783ae93ffffcde08161601f053d686f6315fb0 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:28:01 +0200 Subject: [PATCH 13/24] Make use of 'CConnectedNetConsoleData::m_bInputOnly' properly This member was in the class when RCON was added to the r5sdk, but it was never utilized. Now, each netconsole can toggle whether they are input only or not, the server only sends logs to netconsoles that are not input only. This patch also contains a fix in which the listen server sends logs to the client of its own process, causing an infinite recursive call to DevMsg. --- r5dev/common/callback.cpp | 12 ++++++ r5dev/common/callback.h | 1 + r5dev/common/global.cpp | 6 +-- r5dev/common/global.h | 2 +- r5dev/common/igameserverdata.h | 2 +- r5dev/engine/client/cl_rcon.cpp | 71 +++++++++++++++++++++------------ r5dev/engine/client/cl_rcon.h | 4 ++ r5dev/engine/server/sv_rcon.cpp | 10 +++-- r5dev/netconsole/netconsole.cpp | 2 +- 9 files changed, 75 insertions(+), 35 deletions(-) diff --git a/r5dev/common/callback.cpp b/r5dev/common/callback.cpp index 52c284d3..fa70fa75 100644 --- a/r5dev/common/callback.cpp +++ b/r5dev/common/callback.cpp @@ -991,6 +991,18 @@ void RCON_Disconnect_f(const CCommand& args) DevMsg(eDLL_T::CLIENT, "User closed RCON connection\n"); } } + +/* +===================== +RCON_SendLogs_f + + request logs from RCON server +===================== +*/ +void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue) +{ + RCONClient()->RequestConsoleLog(RCONClient()->ShouldReceive()); +} #endif // !DEDICATED #ifndef CLIENT_DLL diff --git a/r5dev/common/callback.h b/r5dev/common/callback.h index 096c2a67..050627cd 100644 --- a/r5dev/common/callback.h +++ b/r5dev/common/callback.h @@ -50,6 +50,7 @@ void CON_ClearHistory_f(const CCommand& args); void RCON_CmdQuery_f(const CCommand& args); void RCON_Disconnect_f(const CCommand& args); +void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue); #endif // !DEDICATED void RCON_PasswordChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue); #ifndef CLIENT_DLL diff --git a/r5dev/common/global.cpp b/r5dev/common/global.cpp index 1a6cd382..4f24cd20 100644 --- a/r5dev/common/global.cpp +++ b/r5dev/common/global.cpp @@ -144,7 +144,7 @@ ConVar* bhit_abs_origin = nullptr; //----------------------------------------------------------------------------- // CLIENT | #ifndef DEDICATED -ConVar* cl_rcon_request_sendlogs = nullptr; +ConVar* cl_rcon_inputonly = nullptr; ConVar* cl_quota_stringCmdsPerSecond = nullptr; ConVar* cl_cmdrate = nullptr; @@ -322,7 +322,7 @@ void ConVar_StaticInit(void) sv_simulateBots = ConVar::StaticCreate("sv_simulateBots", "1", FCVAR_RELEASE, "Simulate user commands for bots on the server.", true, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_debug = ConVar::StaticCreate("sv_rcon_debug" , "0" , FCVAR_RELEASE, "Show rcon debug information ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); - sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "0" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr); + sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "1" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_banpenalty = ConVar::StaticCreate("sv_rcon_banpenalty" , "10", FCVAR_RELEASE, "Number of minutes to ban users who fail rcon authentication.", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_maxfailures = ConVar::StaticCreate("sv_rcon_maxfailures", "10", FCVAR_RELEASE, "Max number of times a user can fail rcon authentication before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); sv_rcon_maxignores = ConVar::StaticCreate("sv_rcon_maxignores" , "15", FCVAR_RELEASE, "Max number of times a user can ignore the instruction message before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); @@ -343,7 +343,7 @@ void ConVar_StaticInit(void) //------------------------------------------------------------------------- // CLIENT | #ifndef DEDICATED - cl_rcon_request_sendlogs = ConVar::StaticCreate("cl_rcon_request_sendlogs", "1" , FCVAR_RELEASE, "Request the rcon server to send console logs on connect.", false, 0.f, false, 0.f, nullptr, nullptr); + cl_rcon_inputonly = ConVar::StaticCreate("cl_rcon_inputonly", "0" , FCVAR_RELEASE, "Tells the rcon server whether or not we are input only.", false, 0.f, false, 0.f, RCON_InputOnlyChanged_f, nullptr); cl_quota_stringCmdsPerSecond = ConVar::StaticCreate("cl_quota_stringCmdsPerSecond", "16" , FCVAR_RELEASE, "How many string commands per second user is allowed to submit, 0 to allow all submissions.", true, 0.f, false, 0.f, nullptr, nullptr); cl_notify_invert_x = ConVar::StaticCreate("cl_notify_invert_x", "0", FCVAR_DEVELOPMENTONLY, "Inverts the X offset for console notify debug overlay.", false, 0.f, false, 0.f, nullptr, nullptr); diff --git a/r5dev/common/global.h b/r5dev/common/global.h index 95d32c8f..a4d52c20 100644 --- a/r5dev/common/global.h +++ b/r5dev/common/global.h @@ -133,7 +133,7 @@ extern ConVar* bhit_abs_origin; //------------------------------------------------------------------------- // CLIENT | #ifndef DEDICATED -extern ConVar* cl_rcon_request_sendlogs; +extern ConVar* cl_rcon_inputonly; extern ConVar* cl_quota_stringCmdsPerSecond; extern ConVar* cl_cmdrate; diff --git a/r5dev/common/igameserverdata.h b/r5dev/common/igameserverdata.h index fb478f19..fea3e7bd 100644 --- a/r5dev/common/igameserverdata.h +++ b/r5dev/common/igameserverdata.h @@ -49,7 +49,7 @@ public: m_nIgnoredMessage = 0; m_bValidated = false; m_bAuthorized = false; - m_bInputOnly = false; + m_bInputOnly = true; m_RecvBuffer.resize(sizeof(u_long)); // Reserve enough for length-prefix. } }; diff --git a/r5dev/engine/client/cl_rcon.cpp b/r5dev/engine/client/cl_rcon.cpp index a0120ffb..8f2dabd4 100644 --- a/r5dev/engine/client/cl_rcon.cpp +++ b/r5dev/engine/client/cl_rcon.cpp @@ -103,33 +103,12 @@ bool CRConClient::ProcessMessage(const char* pMsgBuf, const int nMsgLen) { if (!response.responseval().empty()) { - const long i = strtol(response.responseval().c_str(), NULL, NULL); - const bool bLocalHost = (g_pNetAdr->ComparePort(m_Address) && g_pNetAdr->CompareAdr(m_Address)); - const char* szEnable = nullptr; - const SocketHandle_t hSocket = GetSocket(); + const int i = atoi(response.responseval().c_str()); - if (!i) // sv_rcon_sendlogs is not set. + // '!i' means we are marked 'input only' on the rcon server. + if (!i && ShouldReceive()) { - if (!bLocalHost && cl_rcon_request_sendlogs->GetBool()) - { - szEnable = "1"; - } - } - else if (bLocalHost) - { - // Don't send logs to local host, it already gets logged to the same console. - szEnable = "0"; - } - - if (szEnable) - { - vector vecMsg; - bool ret = Serialize(vecMsg, "", szEnable, cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG); - - if (ret && !Send(hSocket, vecMsg.data(), int(vecMsg.size()))) - { - Error(eDLL_T::CLIENT, NO_ERROR, "Failed to send RCON message: (%s)\n", "SOCKET_ERROR"); - } + RequestConsoleLog(true); } } @@ -152,6 +131,31 @@ bool CRConClient::ProcessMessage(const char* pMsgBuf, const int nMsgLen) return true; } +//----------------------------------------------------------------------------- +// Purpose: request the rcon server to enable/disable sending logs to us +// Input : bWantLog - +//----------------------------------------------------------------------------- +void CRConClient::RequestConsoleLog(const bool bWantLog) +{ + // If 'IsRemoteLocal()' returns true, and you called this with 'bWantLog' + // true, you caused a bug! It means the server address and port are equal + // to the global netadr singleton, which ultimately means we are running on + // a listen server. Listen server's already log to the same console, + // sending logs will cause the print func to get called recursively forever. + Assert(!(bWantLog && IsRemoteLocal())); + + const char* szEnable = bWantLog ? "1" : "0"; + const SocketHandle_t hSocket = GetSocket(); + + vector vecMsg; + bool ret = Serialize(vecMsg, "", szEnable, cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG); + + if (ret && !Send(hSocket, vecMsg.data(), int(vecMsg.size()))) + { + Error(eDLL_T::CLIENT, NO_ERROR, "Failed to send RCON message: (%s)\n", "SOCKET_ERROR"); + } +} + //----------------------------------------------------------------------------- // Purpose: serializes input // Input : *svReqBuf - @@ -183,6 +187,23 @@ SocketHandle_t CRConClient::GetSocket(void) return SH_GetNetConSocketHandle(this, 0); } +//----------------------------------------------------------------------------- +// Purpose: returns whether or not we should receive logs from the server +// Output : SOCKET_ERROR (-1) on failure +//----------------------------------------------------------------------------- +bool CRConClient::ShouldReceive(void) +{ + return (!IsRemoteLocal() && !cl_rcon_inputonly->GetBool()); +} + +//----------------------------------------------------------------------------- +// Purpose: returns whether the rcon server is actually our own listen server +//----------------------------------------------------------------------------- +bool CRConClient::IsRemoteLocal(void) +{ + return (g_pNetAdr->ComparePort(m_Address) && g_pNetAdr->CompareAdr(m_Address)); +} + //----------------------------------------------------------------------------- // Purpose: checks if client rcon is initialized //----------------------------------------------------------------------------- diff --git a/r5dev/engine/client/cl_rcon.h b/r5dev/engine/client/cl_rcon.h index b4a9903f..72f8a769 100644 --- a/r5dev/engine/client/cl_rcon.h +++ b/r5dev/engine/client/cl_rcon.h @@ -21,6 +21,10 @@ public: bool Serialize(vector& vecBuf, const char* szReqBuf, const char* szReqVal, const cl_rcon::request_t requestType) const; + void RequestConsoleLog(const bool bWantLog); + bool ShouldReceive(void); + + bool IsRemoteLocal(void); bool IsInitialized(void) const; bool IsConnected(void); diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index 4a81a070..034bfc80 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -206,7 +206,7 @@ bool CRConServer::SendToAll(const char* pMsgBuf, const int nMsgLen) const { const CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(i); - if (pData.m_bAuthorized) + if (pData.m_bAuthorized && !pData.m_bInputOnly) { int ret = ::send(pData.m_hSocket, sendbuf.str().data(), int(sendbuf.str().size()), MSG_NOSIGNAL); @@ -334,7 +334,9 @@ void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetCon CloseNonAuthConnection(); } - SendEncode(pData.m_hSocket, s_AuthMessage, sv_rcon_sendlogs->GetString(), + const char* pSendLogs = (!sv_rcon_sendlogs->GetBool() || pData.m_bInputOnly) ? "0" : "1"; + + SendEncode(pData.m_hSocket, s_AuthMessage, pSendLogs, sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast(eDLL_T::NETCON)); } else // Bad password. @@ -424,8 +426,8 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) { if (pData.m_bAuthorized) { - // !TODO[ AMOS ]: Each netcon its own var??? - sv_rcon_sendlogs->SetValue(request.requestval().c_str()); + // "0" means the netconsole is input only. + pData.m_bInputOnly = !atoi(request.requestval().c_str()); } break; } diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index 1736932d..6e843210 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -283,7 +283,7 @@ bool CNetCon::ProcessMessage(const char* pMsgBuf, const int nMsgLen) if (!response.responseval().empty()) { const long i = strtol(response.responseval().c_str(), NULL, NULL); - if (!i) // sv_rcon_sendlogs is not set. + if (!i) // Means we are marked 'input only' on the rcon server. { vector vecMsg; bool ret = Serialize(vecMsg, "", "1", cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG); From bb5e92a5637da2897054ebd25eb54c58cb3c1ae8 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:34:30 +0200 Subject: [PATCH 14/24] Fix redundant socket closing bug Cvar 'sv_rcon_maxsockets' is always higher than the actual allowed socket count. Should only check if its count is higher than the cvar. --- r5dev/engine/server/sv_rcon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index 034bfc80..49c85e3c 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -90,7 +90,7 @@ void CRConServer::Think(void) const int nCount = m_Socket.GetAcceptedSocketCount(); // Close redundant sockets if there are too many except for whitelisted and authenticated. - if (nCount >= sv_rcon_maxsockets->GetInt()) + if (nCount > sv_rcon_maxsockets->GetInt()) { for (m_nConnIndex = nCount - 1; m_nConnIndex >= 0; m_nConnIndex--) { From d7f92cbefd1729abd71f3cdeee7957d43fbebff0 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:41:55 +0200 Subject: [PATCH 15/24] Adjust names Adjust since previously they were pointers but now references. --- r5dev/engine/server/sv_rcon.cpp | 80 +++++++++++++++---------------- r5dev/engine/server/sv_rcon.h | 4 +- r5dev/engine/shared/base_rcon.cpp | 53 ++++++++++---------- r5dev/engine/shared/base_rcon.h | 4 +- 4 files changed, 71 insertions(+), 70 deletions(-) diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index 49c85e3c..25a63cb9 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -97,8 +97,8 @@ void CRConServer::Think(void) const netadr_t& netAdr = m_Socket.GetAcceptedSocketAddress(m_nConnIndex); if (!m_WhiteListAddress.CompareAdr(netAdr)) { - const CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); - if (!pData.m_bAuthorized) + const CConnectedNetConsoleData& data = m_Socket.GetAcceptedSocketData(m_nConnIndex); + if (!data.m_bAuthorized) { Disconnect("redundant"); } @@ -169,18 +169,18 @@ void CRConServer::RunFrame(void) const int nCount = m_Socket.GetAcceptedSocketCount(); for (m_nConnIndex = nCount - 1; m_nConnIndex >= 0; m_nConnIndex--) { - CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); + CConnectedNetConsoleData& data = m_Socket.GetAcceptedSocketData(m_nConnIndex); - if (CheckForBan(pData)) + if (CheckForBan(data)) { - SendEncode(pData.m_hSocket, s_BannedMessage, "", + SendEncode(data.m_hSocket, s_BannedMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, int(eDLL_T::NETCON)); Disconnect("banned"); continue; } - Recv(pData, sv_rcon_maxpacketsize->GetInt()); + Recv(data, sv_rcon_maxpacketsize->GetInt()); } } } @@ -204,11 +204,11 @@ bool CRConServer::SendToAll(const char* pMsgBuf, const int nMsgLen) const const int nCount = m_Socket.GetAcceptedSocketCount(); for (int i = nCount - 1; i >= 0; i--) { - const CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(i); + const CConnectedNetConsoleData& data = m_Socket.GetAcceptedSocketData(i); - if (pData.m_bAuthorized && !pData.m_bInputOnly) + if (data.m_bAuthorized && !data.m_bInputOnly) { - int ret = ::send(pData.m_hSocket, sendbuf.str().data(), + int ret = ::send(data.m_hSocket, sendbuf.str().data(), int(sendbuf.str().size()), MSG_NOSIGNAL); if (ret == SOCKET_ERROR) @@ -315,11 +315,11 @@ bool CRConServer::Serialize(vector& vecBuf, const char* pResponseMsg, cons //----------------------------------------------------------------------------- // Purpose: authenticate new connections // Input : &request - -// *pData - +// &data - //----------------------------------------------------------------------------- -void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetConsoleData& pData) +void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetConsoleData& data) { - if (pData.m_bAuthorized) + if (data.m_bAuthorized) { return; } @@ -327,16 +327,16 @@ void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetCon { if (Comparator(request.requestmsg())) { - pData.m_bAuthorized = true; + data.m_bAuthorized = true; if (++m_nAuthConnections >= sv_rcon_maxconnections->GetInt()) { m_Socket.CloseListenSocket(); CloseNonAuthConnection(); } - const char* pSendLogs = (!sv_rcon_sendlogs->GetBool() || pData.m_bInputOnly) ? "0" : "1"; + const char* pSendLogs = (!sv_rcon_sendlogs->GetBool() || data.m_bInputOnly) ? "0" : "1"; - SendEncode(pData.m_hSocket, s_AuthMessage, pSendLogs, + SendEncode(data.m_hSocket, s_AuthMessage, pSendLogs, sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast(eDLL_T::NETCON)); } else // Bad password. @@ -347,12 +347,12 @@ void CRConServer::Authenticate(const cl_rcon::request& request, CConnectedNetCon DevMsg(eDLL_T::SERVER, "Bad RCON password attempt from '%s'\n", netAdr.ToString()); } - SendEncode(pData.m_hSocket, s_WrongPwMessage, "", + SendEncode(data.m_hSocket, s_WrongPwMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast(eDLL_T::NETCON)); - pData.m_bAuthorized = false; - pData.m_bValidated = false; - pData.m_nFailedAttempts++; + data.m_bAuthorized = false; + data.m_bValidated = false; + data.m_nFailedAttempts++; } } } @@ -387,7 +387,7 @@ bool CRConServer::Comparator(const string& svPassword) const //----------------------------------------------------------------------------- bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) { - CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(m_nConnIndex); + CConnectedNetConsoleData& data = m_Socket.GetAcceptedSocketData(m_nConnIndex); cl_rcon::request request; if (!Decode(&request, pMsgBuf, nMsgLen)) @@ -396,27 +396,27 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) return false; } - if (!pData.m_bAuthorized && + if (!data.m_bAuthorized && request.requesttype() != cl_rcon::request_t::SERVERDATA_REQUEST_AUTH) { // Notify netconsole that authentication is required. - SendEncode(pData.m_hSocket, s_NoAuthMessage, "", + SendEncode(data.m_hSocket, s_NoAuthMessage, "", sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast(eDLL_T::NETCON)); - pData.m_bValidated = false; - pData.m_nIgnoredMessage++; + data.m_bValidated = false; + data.m_nIgnoredMessage++; return true; } switch (request.requesttype()) { case cl_rcon::request_t::SERVERDATA_REQUEST_AUTH: { - Authenticate(request, pData); + Authenticate(request, data); break; } case cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND: { - if (pData.m_bAuthorized) // Only execute if auth was successful. + if (data.m_bAuthorized) // Only execute if auth was successful. { Execute(request); } @@ -424,10 +424,10 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) } case cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG: { - if (pData.m_bAuthorized) + if (data.m_bAuthorized) { // "0" means the netconsole is input only. - pData.m_bInputOnly = !atoi(request.requestval().c_str()); + data.m_bInputOnly = !atoi(request.requestval().c_str()); } break; } @@ -474,11 +474,11 @@ void CRConServer::Execute(const cl_rcon::request& request) const //----------------------------------------------------------------------------- // Purpose: checks for amount of failed attempts and bans netconsole accordingly -// Input : *pData - +// Input : &data - //----------------------------------------------------------------------------- -bool CRConServer::CheckForBan(CConnectedNetConsoleData& pData) +bool CRConServer::CheckForBan(CConnectedNetConsoleData& data) { - if (pData.m_bValidated) + if (data.m_bValidated) { return false; } @@ -509,7 +509,7 @@ bool CRConServer::CheckForBan(CConnectedNetConsoleData& pData) } } - pData.m_bValidated = true; + data.m_bValidated = true; // Check if IP is in the banned list. if (m_BannedList.find(szNetAdr) != m_BannedList.end()) @@ -518,14 +518,14 @@ bool CRConServer::CheckForBan(CConnectedNetConsoleData& pData) } // Check if netconsole has reached maximum number of attempts > add to banned list. - if (pData.m_nFailedAttempts >= sv_rcon_maxfailures->GetInt() - || pData.m_nIgnoredMessage >= sv_rcon_maxignores->GetInt()) + if (data.m_nFailedAttempts >= sv_rcon_maxfailures->GetInt() + || data.m_nIgnoredMessage >= sv_rcon_maxignores->GetInt()) { // Don't add white listed address to banned list. if (m_WhiteListAddress.CompareAdr(netAdr)) { - pData.m_nFailedAttempts = 0; - pData.m_nIgnoredMessage = 0; + data.m_nFailedAttempts = 0; + data.m_nIgnoredMessage = 0; return false; } @@ -551,8 +551,8 @@ void CRConServer::Disconnect(const char* szReason) // NETMGR //----------------------------------------------------------------------------- void CRConServer::Disconnect(const int nIndex, const char* szReason) // NETMGR { - CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(nIndex); - if (pData.m_bAuthorized || sv_rcon_debug->GetBool()) + CConnectedNetConsoleData& data = m_Socket.GetAcceptedSocketData(nIndex); + if (data.m_bAuthorized || sv_rcon_debug->GetBool()) { // Inform server owner when authenticated connection has been closed. netadr_t netAdr = m_Socket.GetAcceptedSocketAddress(nIndex); @@ -576,9 +576,9 @@ void CRConServer::CloseNonAuthConnection(void) int nCount = m_Socket.GetAcceptedSocketCount(); for (int i = nCount - 1; i >= 0; i--) { - CConnectedNetConsoleData& pData = m_Socket.GetAcceptedSocketData(i); + CConnectedNetConsoleData& data = m_Socket.GetAcceptedSocketData(i); - if (!pData.m_bAuthorized) + if (!data.m_bAuthorized) { m_Socket.CloseAcceptedSocket(i); } diff --git a/r5dev/engine/server/sv_rcon.h b/r5dev/engine/server/sv_rcon.h index e7c15688..75465527 100644 --- a/r5dev/engine/server/sv_rcon.h +++ b/r5dev/engine/server/sv_rcon.h @@ -37,13 +37,13 @@ public: bool Serialize(vector& vecBuf, const char* pResponseMsg, const char* pResponseVal, const sv_rcon::response_t responseType, const int nMessageId = static_cast(eDLL_T::NETCON), const int nMessageType = static_cast(LogType_t::LOG_NET)) const; - void Authenticate(const cl_rcon::request& request, CConnectedNetConsoleData& pData); + void Authenticate(const cl_rcon::request& request, CConnectedNetConsoleData& data); bool Comparator(const string& svPassword) const; virtual bool ProcessMessage(const char* pMsgBuf, const int nMsgLen) override; void Execute(const cl_rcon::request& request) const; - bool CheckForBan(CConnectedNetConsoleData& pData); + bool CheckForBan(CConnectedNetConsoleData& data); virtual void Disconnect(const char* szReason = nullptr) override; void Disconnect(const int nIndex, const char* szReason = nullptr); diff --git a/r5dev/engine/shared/base_rcon.cpp b/r5dev/engine/shared/base_rcon.cpp index 64aa9728..063c0544 100644 --- a/r5dev/engine/shared/base_rcon.cpp +++ b/r5dev/engine/shared/base_rcon.cpp @@ -69,16 +69,16 @@ bool CNetConBase::Send(const SocketHandle_t hSocket, const char* pMsgBuf, //----------------------------------------------------------------------------- // Purpose: receive message -// Input : &pData - +// Input : &data - // nMaxLen - // Output: true on success, false otherwise //----------------------------------------------------------------------------- -void CNetConBase::Recv(CConnectedNetConsoleData& pData, const int nMaxLen) +void CNetConBase::Recv(CConnectedNetConsoleData& data, const int nMaxLen) { static char szRecvBuf[1024]; {////////////////////////////////////////////// - const int nPendingLen = ::recv(pData.m_hSocket, szRecvBuf, sizeof(char), MSG_PEEK); + const int nPendingLen = ::recv(data.m_hSocket, szRecvBuf, sizeof(char), MSG_PEEK); if (nPendingLen == SOCKET_ERROR && m_Socket.IsSocketBlocking()) { return; @@ -96,7 +96,7 @@ void CNetConBase::Recv(CConnectedNetConsoleData& pData, const int nMaxLen) }////////////////////////////////////////////// int nReadLen = 0; // Find out how much we have to read. - int iResult = ::ioctlsocket(pData.m_hSocket, FIONREAD, reinterpret_cast(&nReadLen)); + int iResult = ::ioctlsocket(data.m_hSocket, FIONREAD, reinterpret_cast(&nReadLen)); if (iResult == SOCKET_ERROR) { @@ -106,7 +106,7 @@ void CNetConBase::Recv(CConnectedNetConsoleData& pData, const int nMaxLen) while (nReadLen > 0) { - const int nRecvLen = ::recv(pData.m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), MSG_NOSIGNAL); + const int nRecvLen = ::recv(data.m_hSocket, szRecvBuf, MIN(sizeof(szRecvBuf), nReadLen), MSG_NOSIGNAL); if (nRecvLen == 0) // Socket was closed. { Disconnect("socket closed"); @@ -119,7 +119,7 @@ void CNetConBase::Recv(CConnectedNetConsoleData& pData, const int nMaxLen) } nReadLen -= nRecvLen; // Process what we've got. - ProcessBuffer(pData, szRecvBuf, nRecvLen, nMaxLen); + ProcessBuffer(data, szRecvBuf, nRecvLen, nMaxLen); } return; @@ -127,72 +127,73 @@ void CNetConBase::Recv(CConnectedNetConsoleData& pData, const int nMaxLen) //----------------------------------------------------------------------------- // Purpose: parses input response buffer using length-prefix framing -// Input : *pRecvBuf - +// Input : &data - +// *pRecvBuf - // nRecvLen - -// *pData - +// nMaxLen - // Output: true on success, false otherwise //----------------------------------------------------------------------------- -bool CNetConBase::ProcessBuffer(CConnectedNetConsoleData& pData, +bool CNetConBase::ProcessBuffer(CConnectedNetConsoleData& data, const char* pRecvBuf, int nRecvLen, const int nMaxLen) { bool bSuccess = true; while (nRecvLen > 0) { - if (pData.m_nPayloadLen) + if (data.m_nPayloadLen) { - if (pData.m_nPayloadRead < pData.m_nPayloadLen) + if (data.m_nPayloadRead < data.m_nPayloadLen) { - pData.m_RecvBuffer[pData.m_nPayloadRead++] = *pRecvBuf; + data.m_RecvBuffer[data.m_nPayloadRead++] = *pRecvBuf; pRecvBuf++; nRecvLen--; } - if (pData.m_nPayloadRead == pData.m_nPayloadLen) + if (data.m_nPayloadRead == data.m_nPayloadLen) { if (!ProcessMessage( - reinterpret_cast(pData.m_RecvBuffer.data()), pData.m_nPayloadLen) + reinterpret_cast(data.m_RecvBuffer.data()), data.m_nPayloadLen) && bSuccess) { bSuccess = false; } - pData.m_nPayloadLen = 0; - pData.m_nPayloadRead = 0; + data.m_nPayloadLen = 0; + data.m_nPayloadRead = 0; } } - else if (pData.m_nPayloadRead+1 <= sizeof(int)) // Read size field. + else if (data.m_nPayloadRead+1 <= sizeof(int)) // Read size field. { - pData.m_RecvBuffer[pData.m_nPayloadRead++] = *pRecvBuf; + data.m_RecvBuffer[data.m_nPayloadRead++] = *pRecvBuf; pRecvBuf++; nRecvLen--; } else // Build prefix. { - pData.m_nPayloadLen = int(ntohl(*reinterpret_cast(&pData.m_RecvBuffer[0]))); - pData.m_nPayloadRead = 0; + data.m_nPayloadLen = int(ntohl(*reinterpret_cast(&data.m_RecvBuffer[0]))); + data.m_nPayloadRead = 0; - if (!pData.m_bAuthorized && nMaxLen > -1) + if (!data.m_bAuthorized && nMaxLen > -1) { - if (pData.m_nPayloadLen > nMaxLen) + if (data.m_nPayloadLen > nMaxLen) { Disconnect("overflow"); // Sending large messages while not authenticated. return false; } } - if (pData.m_nPayloadLen < 0 || - pData.m_nPayloadLen > pData.m_RecvBuffer.max_size()) + if (data.m_nPayloadLen < 0 || + data.m_nPayloadLen > data.m_RecvBuffer.max_size()) { - Error(eDLL_T::ENGINE, NO_ERROR, "RCON Cmd: sync error (%d)\n", pData.m_nPayloadLen); + Error(eDLL_T::ENGINE, NO_ERROR, "RCON Cmd: sync error (%d)\n", data.m_nPayloadLen); Disconnect("desync"); // Out of sync (irrecoverable). return false; } else { - pData.m_RecvBuffer.resize(pData.m_nPayloadLen); + data.m_RecvBuffer.resize(data.m_nPayloadLen); } } } diff --git a/r5dev/engine/shared/base_rcon.h b/r5dev/engine/shared/base_rcon.h index 5e370c5c..e49b89a6 100644 --- a/r5dev/engine/shared/base_rcon.h +++ b/r5dev/engine/shared/base_rcon.h @@ -18,9 +18,9 @@ public: virtual void Disconnect(const char* szReason = nullptr) { NOTE_UNUSED(szReason); }; virtual bool Send(const SocketHandle_t hSocket, const char* pMsgBuf, const int nMsgLen) const; - virtual void Recv(CConnectedNetConsoleData& pData, const int nMaxLen = SOCKET_ERROR); + virtual void Recv(CConnectedNetConsoleData& data, const int nMaxLen = SOCKET_ERROR); - virtual bool ProcessBuffer(CConnectedNetConsoleData& pData, const char* pRecvBuf, int nRecvLen, const int nMaxLen = SOCKET_ERROR); + virtual bool ProcessBuffer(CConnectedNetConsoleData& data, const char* pRecvBuf, int nRecvLen, const int nMaxLen = SOCKET_ERROR); virtual bool ProcessMessage(const char* /*pMsgBuf*/, int /*nMsgLen*/) { return true; }; CSocketCreator* GetSocketCreator(void) { return &m_Socket; } From 0a25f5e0fe8e8360d382345462220e7b8555460f Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:45:30 +0200 Subject: [PATCH 16/24] Adjust 'CNetConBase' vftable order Order has been adjusted to match the order of execution. --- r5dev/engine/shared/base_rcon.cpp | 174 +++++++++++++++--------------- r5dev/engine/shared/base_rcon.h | 12 +-- 2 files changed, 93 insertions(+), 93 deletions(-) diff --git a/r5dev/engine/shared/base_rcon.cpp b/r5dev/engine/shared/base_rcon.cpp index 063c0544..f7e2fb21 100644 --- a/r5dev/engine/shared/base_rcon.cpp +++ b/r5dev/engine/shared/base_rcon.cpp @@ -8,6 +8,93 @@ #include "engine/net.h" #include "shared_rcon.h" +//----------------------------------------------------------------------------- +// Purpose: connect to remote +// Input : *pHostName - +// nPort - +// Output : true on success, false otherwise +//----------------------------------------------------------------------------- +bool CNetConBase::Connect(const char* pHostName, const int nPort) +{ + return CL_NetConConnect(this, pHostName, nPort); +} + +//----------------------------------------------------------------------------- +// Purpose: parses input response buffer using length-prefix framing +// Input : &data - +// *pRecvBuf - +// nRecvLen - +// nMaxLen - +// Output: true on success, false otherwise +//----------------------------------------------------------------------------- +bool CNetConBase::ProcessBuffer(CConnectedNetConsoleData& data, + const char* pRecvBuf, int nRecvLen, const int nMaxLen) +{ + bool bSuccess = true; + + while (nRecvLen > 0) + { + if (data.m_nPayloadLen) + { + if (data.m_nPayloadRead < data.m_nPayloadLen) + { + data.m_RecvBuffer[data.m_nPayloadRead++] = *pRecvBuf; + + pRecvBuf++; + nRecvLen--; + } + if (data.m_nPayloadRead == data.m_nPayloadLen) + { + if (!ProcessMessage( + reinterpret_cast(data.m_RecvBuffer.data()), data.m_nPayloadLen) + && bSuccess) + { + bSuccess = false; + } + + data.m_nPayloadLen = 0; + data.m_nPayloadRead = 0; + } + } + else if (data.m_nPayloadRead+1 <= sizeof(int)) // Read size field. + { + data.m_RecvBuffer[data.m_nPayloadRead++] = *pRecvBuf; + + pRecvBuf++; + nRecvLen--; + } + else // Build prefix. + { + data.m_nPayloadLen = int(ntohl(*reinterpret_cast(&data.m_RecvBuffer[0]))); + data.m_nPayloadRead = 0; + + if (!data.m_bAuthorized && nMaxLen > -1) + { + if (data.m_nPayloadLen > nMaxLen) + { + Disconnect("overflow"); // Sending large messages while not authenticated. + return false; + } + } + + if (data.m_nPayloadLen < 0 || + data.m_nPayloadLen > data.m_RecvBuffer.max_size()) + { + Error(eDLL_T::ENGINE, NO_ERROR, "RCON Cmd: sync error (%d)\n", data.m_nPayloadLen); + Disconnect("desync"); // Out of sync (irrecoverable). + + return false; + } + else + { + data.m_RecvBuffer.resize(data.m_nPayloadLen); + } + } + } + + return bSuccess; +} + //----------------------------------------------------------------------------- // Purpose: encode message to buffer // Input : *pMsg - @@ -34,17 +121,6 @@ bool CNetConBase::Decode(google::protobuf::MessageLite* pMsg, return pMsg->ParseFromArray(pMsgBuf, int(nMsgLen)); } -//----------------------------------------------------------------------------- -// Purpose: connect to remote -// Input : *pHostName - -// nPort - -// Output : true on success, false otherwise -//----------------------------------------------------------------------------- -bool CNetConBase::Connect(const char* pHostName, const int nPort) -{ - return CL_NetConConnect(this, pHostName, nPort); -} - //----------------------------------------------------------------------------- // Purpose: send message to specific connected socket // Input : hSocket - @@ -124,79 +200,3 @@ void CNetConBase::Recv(CConnectedNetConsoleData& data, const int nMaxLen) return; } - -//----------------------------------------------------------------------------- -// Purpose: parses input response buffer using length-prefix framing -// Input : &data - -// *pRecvBuf - -// nRecvLen - -// nMaxLen - -// Output: true on success, false otherwise -//----------------------------------------------------------------------------- -bool CNetConBase::ProcessBuffer(CConnectedNetConsoleData& data, - const char* pRecvBuf, int nRecvLen, const int nMaxLen) -{ - bool bSuccess = true; - - while (nRecvLen > 0) - { - if (data.m_nPayloadLen) - { - if (data.m_nPayloadRead < data.m_nPayloadLen) - { - data.m_RecvBuffer[data.m_nPayloadRead++] = *pRecvBuf; - - pRecvBuf++; - nRecvLen--; - } - if (data.m_nPayloadRead == data.m_nPayloadLen) - { - if (!ProcessMessage( - reinterpret_cast(data.m_RecvBuffer.data()), data.m_nPayloadLen) - && bSuccess) - { - bSuccess = false; - } - - data.m_nPayloadLen = 0; - data.m_nPayloadRead = 0; - } - } - else if (data.m_nPayloadRead+1 <= sizeof(int)) // Read size field. - { - data.m_RecvBuffer[data.m_nPayloadRead++] = *pRecvBuf; - - pRecvBuf++; - nRecvLen--; - } - else // Build prefix. - { - data.m_nPayloadLen = int(ntohl(*reinterpret_cast(&data.m_RecvBuffer[0]))); - data.m_nPayloadRead = 0; - - if (!data.m_bAuthorized && nMaxLen > -1) - { - if (data.m_nPayloadLen > nMaxLen) - { - Disconnect("overflow"); // Sending large messages while not authenticated. - return false; - } - } - - if (data.m_nPayloadLen < 0 || - data.m_nPayloadLen > data.m_RecvBuffer.max_size()) - { - Error(eDLL_T::ENGINE, NO_ERROR, "RCON Cmd: sync error (%d)\n", data.m_nPayloadLen); - Disconnect("desync"); // Out of sync (irrecoverable). - - return false; - } - else - { - data.m_RecvBuffer.resize(data.m_nPayloadLen); - } - } - } - - return bSuccess; -} diff --git a/r5dev/engine/shared/base_rcon.h b/r5dev/engine/shared/base_rcon.h index e49b89a6..f46ad20e 100644 --- a/r5dev/engine/shared/base_rcon.h +++ b/r5dev/engine/shared/base_rcon.h @@ -11,18 +11,18 @@ public: CNetConBase(void) {} - virtual bool Encode(google::protobuf::MessageLite* pMsg, char* pMsgBuf, const size_t nMsgLen) const; - virtual bool Decode(google::protobuf::MessageLite* pMsg, const char* pMsgBuf, const size_t nMsgLen) const; - virtual bool Connect(const char* pHostAdr, const int nHostPort = SOCKET_ERROR); virtual void Disconnect(const char* szReason = nullptr) { NOTE_UNUSED(szReason); }; - virtual bool Send(const SocketHandle_t hSocket, const char* pMsgBuf, const int nMsgLen) const; - virtual void Recv(CConnectedNetConsoleData& data, const int nMaxLen = SOCKET_ERROR); - virtual bool ProcessBuffer(CConnectedNetConsoleData& data, const char* pRecvBuf, int nRecvLen, const int nMaxLen = SOCKET_ERROR); virtual bool ProcessMessage(const char* /*pMsgBuf*/, int /*nMsgLen*/) { return true; }; + virtual bool Encode(google::protobuf::MessageLite* pMsg, char* pMsgBuf, const size_t nMsgLen) const; + virtual bool Decode(google::protobuf::MessageLite* pMsg, const char* pMsgBuf, const size_t nMsgLen) const; + + virtual bool Send(const SocketHandle_t hSocket, const char* pMsgBuf, const int nMsgLen) const; + virtual void Recv(CConnectedNetConsoleData& data, const int nMaxLen = SOCKET_ERROR); + CSocketCreator* GetSocketCreator(void) { return &m_Socket; } netadr_t* GetNetAddress(void) { return &m_Address; } From 5e4ea7d25aa4dc669dbec04bd9d891b7c096233f Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 5 Aug 2023 01:09:53 +0200 Subject: [PATCH 17/24] Minor convar string stuff --- r5dev/common/global.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/r5dev/common/global.cpp b/r5dev/common/global.cpp index 4f24cd20..5a64de03 100644 --- a/r5dev/common/global.cpp +++ b/r5dev/common/global.cpp @@ -271,9 +271,9 @@ void ConVar_StaticInit(void) hostdesc = ConVar::StaticCreate("hostdesc", "", FCVAR_RELEASE, "Host game server description.", false, 0.f, false, 0.f, nullptr, nullptr); sdk_fixedframe_tickinterval = ConVar::StaticCreate("sdk_fixedframe_tickinterval", "0.01", FCVAR_RELEASE, "The tick interval used by the SDK fixed frame.", false, 0.f, false, 0.f, nullptr, nullptr); - curl_debug = ConVar::StaticCreate("curl_debug" , "0" , FCVAR_DEVELOPMENTONLY, "Determines whether or not to enable curl debug logging.", false, 0.f, false, 0.f, nullptr, "1 = curl logs; 0 (zero) = no logs."); + curl_debug = ConVar::StaticCreate("curl_debug" , "0" , FCVAR_DEVELOPMENTONLY, "Determines whether or not to enable curl debug logging.", false, 0.f, false, 0.f, nullptr, "1 = curl logs; 0 (zero) = no logs"); curl_timeout = ConVar::StaticCreate("curl_timeout" , "15", FCVAR_DEVELOPMENTONLY, "Maximum time in seconds a curl transfer operation could take.", false, 0.f, false, 0.f, nullptr, nullptr); - ssl_verify_peer = ConVar::StaticCreate("ssl_verify_peer", "1" , FCVAR_DEVELOPMENTONLY, "Verify the authenticity of the peer's SSL certificate.", false, 0.f, false, 0.f, nullptr, "1 = curl verifies; 0 (zero) = no verification."); + ssl_verify_peer = ConVar::StaticCreate("ssl_verify_peer", "1" , FCVAR_DEVELOPMENTONLY, "Verify the authenticity of the peer's SSL certificate.", false, 0.f, false, 0.f, nullptr, "1 = curl verifies; 0 (zero) = no verification"); rcon_address = ConVar::StaticCreate("rcon_address", "[loopback]:37015", FCVAR_SERVER_CANNOT_QUERY | FCVAR_DONTRECORD | FCVAR_RELEASE, "Remote server access address.", false, 0.f, false, 0.f, nullptr, nullptr); rcon_password = ConVar::StaticCreate("rcon_password", "" , FCVAR_SERVER_CANNOT_QUERY | FCVAR_DONTRECORD | FCVAR_RELEASE, "Remote server access password (rcon is disabled if empty).", false, 0.f, false, 0.f, &RCON_PasswordChanged_f, nullptr); @@ -311,7 +311,7 @@ void ConVar_StaticInit(void) navmesh_draw_poly_bounds_inner = ConVar::StaticCreate("navmesh_draw_poly_bounds_inner" , "0" , FCVAR_DEVELOPMENTONLY, "Draws the inner bounds of the NavMesh polys (requires navmesh_draw_poly_bounds).", false, 0.f, false, 0.f, nullptr, "Index: > 0 && < mesh->m_tileCount"); #endif // !DEDICATED - sv_language = ConVar::StaticCreate("sv_language", "english", FCVAR_RELEASE, "Language of the server. Sent to MasterServer for localising error messages", false, 0.f, false, 0.f, SV_LanguageChanged_f, nullptr); + sv_language = ConVar::StaticCreate("sv_language", "english", FCVAR_RELEASE, "Language of the server. Sent to MasterServer for localising error messages.", false, 0.f, false, 0.f, SV_LanguageChanged_f, nullptr); sv_showconnecting = ConVar::StaticCreate("sv_showconnecting" , "1", FCVAR_RELEASE, "Logs information about the connecting client to the console.", false, 0.f, false, 0.f, nullptr, nullptr); sv_globalBanlist = ConVar::StaticCreate("sv_globalBanlist" , "1", FCVAR_RELEASE, "Determines whether or not to use the global banned list.", false, 0.f, false, 0.f, nullptr, "0 = Disable, 1 = Enable."); sv_pylonVisibility = ConVar::StaticCreate("sv_pylonVisibility", "0", FCVAR_RELEASE, "Determines the visibility to the Pylon master server.", false, 0.f, false, 0.f, nullptr, "0 = Offline, 1 = Hidden, 2 = Public."); @@ -324,8 +324,8 @@ void ConVar_StaticInit(void) sv_rcon_debug = ConVar::StaticCreate("sv_rcon_debug" , "0" , FCVAR_RELEASE, "Show rcon debug information ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "1" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_banpenalty = ConVar::StaticCreate("sv_rcon_banpenalty" , "10", FCVAR_RELEASE, "Number of minutes to ban users who fail rcon authentication.", false, 0.f, false, 0.f, nullptr, nullptr); - sv_rcon_maxfailures = ConVar::StaticCreate("sv_rcon_maxfailures", "10", FCVAR_RELEASE, "Max number of times a user can fail rcon authentication before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); - sv_rcon_maxignores = ConVar::StaticCreate("sv_rcon_maxignores" , "15", FCVAR_RELEASE, "Max number of times a user can ignore the instruction message before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); + sv_rcon_maxfailures = ConVar::StaticCreate("sv_rcon_maxfailures", "10", FCVAR_RELEASE, "Max number of times an user can fail rcon authentication before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); + sv_rcon_maxignores = ConVar::StaticCreate("sv_rcon_maxignores" , "15", FCVAR_RELEASE, "Max number of times an user can ignore the instruction message before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); sv_rcon_maxsockets = ConVar::StaticCreate("sv_rcon_maxsockets" , "32", FCVAR_RELEASE, "Max number of accepted sockets before the server starts closing redundant sockets.", true, 1.f, true, MAX_PLAYERS, nullptr, nullptr); sv_rcon_maxconnections = ConVar::StaticCreate("sv_rcon_maxconnections" , "1" , FCVAR_RELEASE, "Max number of authenticated connections before the server closes the listen socket.", true, 1.f, true, MAX_PLAYERS, &RCON_ConnectionCountChanged_f, nullptr); sv_rcon_maxpacketsize = ConVar::StaticCreate("sv_rcon_maxpacketsize" , "1024", FCVAR_RELEASE, "Max number of bytes allowed in a command packet from a non-authenticated netconsole.", true, 0.f, false, 0.f, nullptr, nullptr); @@ -414,11 +414,11 @@ void ConVar_StaticInit(void) usercmd_dualwield_enable = ConVar::StaticCreate("usercmd_dualwield_enable", "0", FCVAR_REPLICATED | FCVAR_RELEASE, "Allows setting dual wield cycle slots, and activating multiple inventory weapons from UserCmd.", false, 0.f, false, 0.f, nullptr, nullptr); //------------------------------------------------------------------------- // FILESYSTEM | - fs_showWarnings = ConVar::StaticCreate("fs_showWarnings" , "0", FCVAR_DEVELOPMENTONLY, "Logs the FileSystem warnings to the console, filtered by 'fs_warning_level' ( !slower! ).", true, 0.f, true, 2.f, nullptr, "0 = log to file. 1 = 0 + log to console. 2 = 1 + log to notify."); + fs_showWarnings = ConVar::StaticCreate("fs_showWarnings" , "0", FCVAR_DEVELOPMENTONLY, "Logs the FileSystem warnings to the console, filtered by 'fs_warning_level' ( !slower! ).", true, 0.f, true, 2.f, nullptr, "0 = log to file. 1 = 0 + log to console. 2 = 1 + log to notify"); fs_packedstore_entryblock_stats = ConVar::StaticCreate("fs_packedstore_entryblock_stats" , "0", FCVAR_DEVELOPMENTONLY, "Logs the stats of each file entry in the VPK during decompression ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); fs_packedstore_workspace = ConVar::StaticCreate("fs_packedstore_workspace" , "ship", FCVAR_DEVELOPMENTONLY, "Determines the current VPK workspace.", false, 0.f, false, 0.f, nullptr, nullptr); fs_packedstore_compression_level = ConVar::StaticCreate("fs_packedstore_compression_level", "default", FCVAR_DEVELOPMENTONLY, "Determines the VPK compression level.", false, 0.f, false, 0.f, nullptr, "fastest faster default better uber"); - fs_packedstore_max_helper_threads = ConVar::StaticCreate("fs_packedstore_max_helper_threads" , "-1", FCVAR_DEVELOPMENTONLY, "Max # of additional \"helper\" threads to create during compression.", true, -1, true, LZHAM_MAX_HELPER_THREADS, nullptr, "Must range between [-1,LZHAM_MAX_HELPER_THREADS], where -1=max practical."); + fs_packedstore_max_helper_threads = ConVar::StaticCreate("fs_packedstore_max_helper_threads" , "-1", FCVAR_DEVELOPMENTONLY, "Max # of additional \"helper\" threads to create during compression.", true, -1, true, LZHAM_MAX_HELPER_THREADS, nullptr, "Must range between [-1,LZHAM_MAX_HELPER_THREADS], where -1=max practical"); //------------------------------------------------------------------------- // MATERIALSYSTEM | #ifndef DEDICATED @@ -426,14 +426,14 @@ void ConVar_StaticInit(void) #endif // !DEDICATED //------------------------------------------------------------------------- // SQUIRREL | - script_show_output = ConVar::StaticCreate("script_show_output" , "0", FCVAR_RELEASE, "Prints the VM output to the console ( !slower! ).", true, 0.f, true, 2.f, nullptr, "0 = log to file. 1 = 0 + log to console. 2 = 1 + log to notify."); - script_show_warning = ConVar::StaticCreate("script_show_warning", "0", FCVAR_RELEASE, "Prints the VM warning output to the console ( !slower! ).", true, 0.f, true, 2.f, nullptr, "0 = log to file. 1 = 0 + log to console. 2 = 1 + log to notify."); + script_show_output = ConVar::StaticCreate("script_show_output" , "0", FCVAR_RELEASE, "Prints the VM output to the console ( !slower! ).", true, 0.f, true, 2.f, nullptr, "0 = log to file. 1 = 0 + log to console. 2 = 1 + log to notify"); + script_show_warning = ConVar::StaticCreate("script_show_warning", "0", FCVAR_RELEASE, "Prints the VM warning output to the console ( !slower! ).", true, 0.f, true, 2.f, nullptr, "0 = log to file. 1 = 0 + log to console. 2 = 1 + log to notify"); //------------------------------------------------------------------------- // NETCHANNEL | net_tracePayload = ConVar::StaticCreate("net_tracePayload" , "0", FCVAR_DEVELOPMENTONLY , "Log the payload of the send/recv datagram to a file on the disk.", false, 0.f, false, 0.f, nullptr, nullptr); net_encryptionEnable = ConVar::StaticCreate("net_encryptionEnable" , "1", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED , "Use AES encryption on game packets.", false, 0.f, false, 0.f, nullptr, nullptr); net_useRandomKey = ConVar::StaticCreate("net_useRandomKey" , "1" , FCVAR_RELEASE , "Use random AES encryption key for game packets.", false, 0.f, false, 0.f, &NET_UseRandomKeyChanged_f, nullptr); - net_processTimeBudget = ConVar::StaticCreate("net_processTimeBudget" ,"200" , FCVAR_RELEASE , "Net message process time budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled."); + net_processTimeBudget = ConVar::StaticCreate("net_processTimeBudget" ,"200" , FCVAR_RELEASE , "Net message process time budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled"); //------------------------------------------------------------------------- // NETWORKSYSTEM | pylon_matchmaking_hostname = ConVar::StaticCreate("pylon_matchmaking_hostname", "ms.r5reloaded.com", FCVAR_RELEASE, "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr); @@ -445,12 +445,12 @@ void ConVar_StaticInit(void) //------------------------------------------------------------------------- // RUI | #ifndef DEDICATED - rui_drawEnable = ConVar::StaticCreate("rui_drawEnable", "1", FCVAR_RELEASE, "Draws the RUI if set.", false, 0.f, false, 0.f, nullptr, "1 = Draw, 0 = No Draw."); + rui_drawEnable = ConVar::StaticCreate("rui_drawEnable", "1", FCVAR_RELEASE, "Draws the RUI if set.", false, 0.f, false, 0.f, nullptr, "1 = draw; 0 (zero) = no draw"); #endif // !DEDICATED //------------------------------------------------------------------------- // MILES | #ifndef DEDICATED - miles_debug = ConVar::StaticCreate("miles_debug", "0", FCVAR_RELEASE, "Enables debug prints for the Miles Sound System.", false, 0.f, false, 0.f, nullptr, "1 = Print, 0 = No Print"); + miles_debug = ConVar::StaticCreate("miles_debug", "0", FCVAR_RELEASE, "Enables debug prints for the Miles Sound System.", false, 0.f, false, 0.f, nullptr, "1 = print; 0 (zero) = no print"); #endif // !DEDICATED //------------------------------------------------------------------------- } From 759d8d6d2e183f615dd5925a641734f336628e8b Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 5 Aug 2023 01:11:32 +0200 Subject: [PATCH 18/24] Flip 'sv_rcon_sendlogs' if netcon is not input only --- r5dev/common/global.cpp | 2 +- r5dev/engine/server/sv_rcon.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/r5dev/common/global.cpp b/r5dev/common/global.cpp index 5a64de03..6c5770b9 100644 --- a/r5dev/common/global.cpp +++ b/r5dev/common/global.cpp @@ -322,7 +322,7 @@ void ConVar_StaticInit(void) sv_simulateBots = ConVar::StaticCreate("sv_simulateBots", "1", FCVAR_RELEASE, "Simulate user commands for bots on the server.", true, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_debug = ConVar::StaticCreate("sv_rcon_debug" , "0" , FCVAR_RELEASE, "Show rcon debug information ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); - sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "1" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr); + sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "0" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_banpenalty = ConVar::StaticCreate("sv_rcon_banpenalty" , "10", FCVAR_RELEASE, "Number of minutes to ban users who fail rcon authentication.", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_maxfailures = ConVar::StaticCreate("sv_rcon_maxfailures", "10", FCVAR_RELEASE, "Max number of times an user can fail rcon authentication before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); sv_rcon_maxignores = ConVar::StaticCreate("sv_rcon_maxignores" , "15", FCVAR_RELEASE, "Max number of times an user can ignore the instruction message before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index 25a63cb9..321a2921 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -426,8 +426,16 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) { if (data.m_bAuthorized) { - // "0" means the netconsole is input only. - data.m_bInputOnly = !atoi(request.requestval().c_str()); + // request value "0" means the netconsole is input only. + const bool bWantLog = atoi(request.requestval().c_str()) != NULL; + + data.m_bInputOnly = !bWantLog; + if (bWantLog && !sv_rcon_sendlogs->GetBool()) + { + // Toggle it on since there's at least 1 netconsole that + // wants to receive logs. + sv_rcon_sendlogs->SetValue(bWantLog); + } } break; } From 2d6a1c79acfb39a9b558a6cfad6638bf87268efb Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 5 Aug 2023 01:14:03 +0200 Subject: [PATCH 19/24] Comment 'sv_rcon_banpenalty' out for now Nice to implement at some point, but its not a priority. The current system just disables itself if its under attack (requires action from server owner to re-enable). --- r5dev/common/global.cpp | 4 ++-- r5dev/common/global.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/r5dev/common/global.cpp b/r5dev/common/global.cpp index 6c5770b9..e0fe8273 100644 --- a/r5dev/common/global.cpp +++ b/r5dev/common/global.cpp @@ -124,7 +124,7 @@ ConVar* player_userCmdsQueueWarning = nullptr; //#ifdef DEDICATED ConVar* sv_rcon_debug = nullptr; ConVar* sv_rcon_sendlogs = nullptr; -ConVar* sv_rcon_banpenalty = nullptr; // TODO +//ConVar* sv_rcon_banpenalty = nullptr; // TODO ConVar* sv_rcon_maxfailures = nullptr; ConVar* sv_rcon_maxignores = nullptr; ConVar* sv_rcon_maxsockets = nullptr; @@ -323,7 +323,7 @@ void ConVar_StaticInit(void) sv_rcon_debug = ConVar::StaticCreate("sv_rcon_debug" , "0" , FCVAR_RELEASE, "Show rcon debug information ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "0" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr); - sv_rcon_banpenalty = ConVar::StaticCreate("sv_rcon_banpenalty" , "10", FCVAR_RELEASE, "Number of minutes to ban users who fail rcon authentication.", false, 0.f, false, 0.f, nullptr, nullptr); + //sv_rcon_banpenalty = ConVar::StaticCreate("sv_rcon_banpenalty" , "10", FCVAR_RELEASE, "Number of minutes to ban users who fail rcon authentication.", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_maxfailures = ConVar::StaticCreate("sv_rcon_maxfailures", "10", FCVAR_RELEASE, "Max number of times an user can fail rcon authentication before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); sv_rcon_maxignores = ConVar::StaticCreate("sv_rcon_maxignores" , "15", FCVAR_RELEASE, "Max number of times an user can ignore the instruction message before being banned.", true, 1.f, false, 0.f, nullptr, nullptr); sv_rcon_maxsockets = ConVar::StaticCreate("sv_rcon_maxsockets" , "32", FCVAR_RELEASE, "Max number of accepted sockets before the server starts closing redundant sockets.", true, 1.f, true, MAX_PLAYERS, nullptr, nullptr); diff --git a/r5dev/common/global.h b/r5dev/common/global.h index a4d52c20..4015abd7 100644 --- a/r5dev/common/global.h +++ b/r5dev/common/global.h @@ -113,7 +113,7 @@ extern ConVar* player_userCmdsQueueWarning; //#ifdef DEDICATED extern ConVar* sv_rcon_debug; extern ConVar* sv_rcon_sendlogs; -extern ConVar* sv_rcon_banpenalty; +//extern ConVar* sv_rcon_banpenalty; extern ConVar* sv_rcon_maxfailures; extern ConVar* sv_rcon_maxignores; extern ConVar* sv_rcon_maxsockets; From 3ca092f5985040bbbbe40e2f63556b88ab9efcb2 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 5 Aug 2023 20:29:07 +0200 Subject: [PATCH 20/24] Temporarily fix convar value assignment bug in 'CRConServer::Execute()' Command string buffer contains "sv_cheats" and value buffer contains "sv_cheats 1". Ideally value buffer only contains "1", and we just concatenate to "sv_cheats 1" for 'Cmd_Dispatch()' to avoid confusion on the netconsole's programmer side. This will be refactored in the future. --- r5dev/engine/server/sv_rcon.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index 321a2921..f331425d 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -454,7 +454,9 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) //----------------------------------------------------------------------------- void CRConServer::Execute(const cl_rcon::request& request) const { - const char* pCommandString = request.requestmsg().c_str(); + const string& commandString = request.requestmsg().c_str(); + const char* const pCommandString = commandString.c_str(); + ConCommandBase* pCommandBase = g_pCVar->FindCommandBase(pCommandString); if (!pCommandBase) @@ -463,13 +465,29 @@ void CRConServer::Execute(const cl_rcon::request& request) const return; } - const bool isCommand = pCommandBase->IsCommand(); - const char* pValueString = request.requestval().c_str(); + const char* const pValueString = request.requestval().c_str(); - if (!isCommand) + if (!pCommandBase->IsCommand()) { + // Here we want to skip over the command string in the value buffer. + // So if we got 'sv_cheats 1' in our value buffer, we want to skip + // over 'sv_cheats ', so that we are pointing directly to the value. + const char* pFound = V_strstr(pValueString, pCommandString); + const char* pValue = nullptr; + + if (pFound) + { + pValue = pFound + commandString.length(); + + // Skip any leading space characters. + while (*pValue == ' ') + { + ++pValue; + } + } + ConVar* pConVar = reinterpret_cast(pCommandBase); - pConVar->SetValue(pValueString); + pConVar->SetValue(pValue ? pValue : pValueString); } else // Invoke command callback directly. { From 89431cc61f247825c277264b3114a2f42481ab73 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:52:35 +0200 Subject: [PATCH 21/24] Fix crasher by clamping stringcmd length before tokenizing it Possible crasher is to send a stringcmd >= 512 in size with funny UTF8 characters and have CUtlBuffer::ParseToken() read past it. Apparently seems to be mostly a problem on 32bit? I was unable to initiate a crash, though one string caused interesting behavior before, and there was one report of the dedicated server being 'crashed' with this. There is no reason to tokenize it up to 512 bytes if the game is only ever going to allow 128, so clamp it to 129 and if the user exceeds it then they still get the message and we just jettison it. --- r5dev/engine/client/client.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/r5dev/engine/client/client.cpp b/r5dev/engine/client/client.cpp index c258a304..85315e74 100644 --- a/r5dev/engine/client/client.cpp +++ b/r5dev/engine/client/client.cpp @@ -14,6 +14,9 @@ #include "engine/server/server.h" #include "engine/client/client.h" +// 128+1 so that the client still receives the 'console command too long' message. +#define STRINGCMD_MAX_LEN 129 + //--------------------------------------------------------------------------------- // Purpose: throw away any residual garbage in the channel //--------------------------------------------------------------------------------- @@ -177,13 +180,29 @@ bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg) // Just skip if the cmd pointer is null, we still check if the // client sent too many commands and take appropriate actions. // The internal function discards the command if it's null. - if (pCmd && !V_IsValidUTF8(pCmd)) + if (pCmd) { - Warning(eDLL_T::SERVER, "Removing client '%s' from slot #%i ('%llu' sent invalid string command!)\n", - pClient_Adj->GetNetChan()->GetAddress(), pClient_Adj->GetUserID(), pClient_Adj->GetNucleusID()); + // If the string length exceeds 128, the will engine return a 'command + // string too long' message back to the client that issued it and + // subsequently jettison the string cmd. Before this routine gets hit, + // the entire string gets parsed (up to 512 bytes). There is an issue + // in CUtlBuffer::ParseToken() that causes it to read past its buffer; + // mostly seems to happen on 32bit, but a carefully crafted string + // should work on 64bit too). The fix is to just null everything past + // the maximum allowed length. The second 'theoretical' fix would be to + // properly fix CUtlBuffer::ParseToken() by computing the UTF8 character + // size each iteration and check if it still doesn't exceed bounds. + memset(&pMsg->buffer[STRINGCMD_MAX_LEN], + '\0', sizeof(pMsg->buffer) - (STRINGCMD_MAX_LEN)); - pClient_Adj->Disconnect(Reputation_t::REP_MARK_BAD, "#DISCONNECT_INVALID_STRINGCMD"); - return true; + if (!V_IsValidUTF8(pCmd)) + { + Warning(eDLL_T::SERVER, "Removing client '%s' from slot #%i ('%llu' sent invalid string command!)\n", + pClient_Adj->GetNetChan()->GetAddress(), pClient_Adj->GetUserID(), pClient_Adj->GetNucleusID()); + + pClient_Adj->Disconnect(Reputation_t::REP_MARK_BAD, "#DISCONNECT_INVALID_STRINGCMD"); + return true; + } } if (flStartTime - pSlot->m_flStringCommandQuotaTimeStart >= 1.0) From a840fd14939047db25bdf5d5560574ecb73b60fb Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 7 Aug 2023 17:54:57 +0200 Subject: [PATCH 22/24] Remove devonly flag from 'discord_updatePresence' Allow user to enable it, seems to work perfectly fine. --- r5dev/common/global.cpp | 3 +++ r5dev/common/global.h | 1 + 2 files changed, 4 insertions(+) diff --git a/r5dev/common/global.cpp b/r5dev/common/global.cpp index e0fe8273..101b9c86 100644 --- a/r5dev/common/global.cpp +++ b/r5dev/common/global.cpp @@ -206,6 +206,7 @@ ConVar* con_suggest_showhelptext = nullptr; ConVar* con_suggest_showflags = nullptr; ConVar* origin_disconnectWhenOffline = nullptr; +ConVar* discord_updatePresence = nullptr; ConVar* serverbrowser_hideEmptyServers = nullptr; ConVar* serverbrowser_mapFilter = nullptr; @@ -495,6 +496,7 @@ void ConVar_InitShipped(void) old_gather_props = g_pCVar->FindVar("old_gather_props"); #ifndef DEDICATED origin_disconnectWhenOffline = g_pCVar->FindVar("origin_disconnectWhenOffline"); + discord_updatePresence = g_pCVar->FindVar("discord_updatePresence"); #endif // !DEDICATED mp_gamemode = g_pCVar->FindVar("mp_gamemode"); ip_cvar = g_pCVar->FindVar("ip"); @@ -538,6 +540,7 @@ void ConVar_InitShipped(void) cl_threaded_bone_setup->RemoveFlags(FCVAR_DEVELOPMENTONLY); rui_defaultDebugFontFace->RemoveFlags(FCVAR_DEVELOPMENTONLY); origin_disconnectWhenOffline->RemoveFlags(FCVAR_DEVELOPMENTONLY); + discord_updatePresence->RemoveFlags(FCVAR_DEVELOPMENTONLY); #endif // !DEDICATED mp_gamemode->RemoveFlags(FCVAR_DEVELOPMENTONLY); mp_gamemode->RemoveChangeCallback(mp_gamemode->m_fnChangeCallbacks[0]); diff --git a/r5dev/common/global.h b/r5dev/common/global.h index 4015abd7..2fa7d671 100644 --- a/r5dev/common/global.h +++ b/r5dev/common/global.h @@ -195,6 +195,7 @@ extern ConVar* con_suggest_showhelptext; extern ConVar* con_suggest_showflags; extern ConVar* origin_disconnectWhenOffline; +extern ConVar* discord_updatePresence; #endif // !DEDICATED //------------------------------------------------------------------------- // FILESYSTEM | From 704900e2cd91fe5a8e8f0e14906962af83df3137 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 7 Aug 2023 21:23:42 +0200 Subject: [PATCH 23/24] Don't index into it again Use the already cached reference. --- r5dev/vgui/vgui_debugpanel.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/r5dev/vgui/vgui_debugpanel.cpp b/r5dev/vgui/vgui_debugpanel.cpp index 99e76259..24e83ea3 100644 --- a/r5dev/vgui/vgui_debugpanel.cpp +++ b/r5dev/vgui/vgui_debugpanel.cpp @@ -86,14 +86,14 @@ void CTextOverlay::DrawNotify(void) std::lock_guard l(m_Mutex); for (size_t i = 0, j = m_vNotifyText.size(); i < j; i++) { - CTextNotify* pNotify = &m_vNotifyText[i]; - Color c = GetLogColorForType(m_vNotifyText[i].m_type); + const CTextNotify& notify = m_vNotifyText[i]; + Color c = GetLogColorForType(notify.m_type); - float flTimeleft = pNotify->m_flLifeRemaining; + const float flTimeleft = notify.m_flLifeRemaining; if (flTimeleft < 1.0f) { - float f = clamp(flTimeleft, 0.0f, 1.0f) / 1.0f; + const float f = clamp(flTimeleft, 0.0f, 1.0f) / 1.0f; c[3] = uint8_t(f * 255.0f); if (i == 0 && f < 0.2f) @@ -106,7 +106,7 @@ void CTextOverlay::DrawNotify(void) c[3] = 255; } CMatSystemSurface_DrawColoredText(g_pMatSystemSurface, v_Rui_GetFontFace(), - m_nFontHeight, x, y, c.r(), c.g(), c.b(), c.a(), "%s", m_vNotifyText[i].m_svMessage.c_str()); + m_nFontHeight, x, y, c.r(), c.g(), c.b(), c.a(), "%s", notify.m_svMessage.c_str()); if (IsX360()) { From 822d9f2b19689a614fccca9a38e8763567117bc7 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 7 Aug 2023 22:10:06 +0200 Subject: [PATCH 24/24] CTextOverlay cleanup Slightly improved performance, reduced number of copy constructions, reduced number of integral type casts by just using the CUtlVector class. --- r5dev/core/logger.cpp | 2 +- r5dev/vgui/vgui_debugpanel.cpp | 41 +++++++++++++++++----------------- r5dev/vgui/vgui_debugpanel.h | 20 ++++++++--------- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/r5dev/core/logger.cpp b/r5dev/core/logger.cpp index 67e665d4..765ccef9 100644 --- a/r5dev/core/logger.cpp +++ b/r5dev/core/logger.cpp @@ -297,7 +297,7 @@ void EngineLoggerSink(LogType_t logType, LogLevel_t logLevel, eDLL_T context, if (g_bSdkInitialized && logLevel >= LogLevel_t::LEVEL_NOTIFY) { // Draw to mini console. - g_pOverlay->AddLog(overlayContext, logStreamBuf); + g_pOverlay->AddLog(overlayContext, logStreamBuf.c_str()); } #endif // !DEDICATED } diff --git a/r5dev/vgui/vgui_debugpanel.cpp b/r5dev/vgui/vgui_debugpanel.cpp index 24e83ea3..d2a1fb1b 100644 --- a/r5dev/vgui/vgui_debugpanel.cpp +++ b/r5dev/vgui/vgui_debugpanel.cpp @@ -58,20 +58,20 @@ void CTextOverlay::Update(void) //----------------------------------------------------------------------------- // Purpose: add a log to the vector. //----------------------------------------------------------------------------- -void CTextOverlay::AddLog(const eDLL_T context, const string& svText) +void CTextOverlay::AddLog(const eDLL_T context, const char* pszText) { - if (!con_drawnotify->GetBool() || svText.empty()) + if (!con_drawnotify->GetBool() || !VALID_CHARSTAR(pszText)) { return; } - std::lock_guard l(m_Mutex); - m_vNotifyText.push_back(CTextNotify{ context, con_notifytime->GetFloat() , svText }); + AUTO_LOCK(m_Mutex); + m_NotifyLines.AddToTail(CTextNotify{ context, con_notifytime->GetFloat() , pszText }); - while (m_vNotifyText.size() > 0 && - (m_vNotifyText.size() > con_notifylines->GetInt())) + while (m_NotifyLines.Count() > 0 && + (m_NotifyLines.Count() > con_notifylines->GetInt())) { - m_vNotifyText.erase(m_vNotifyText.begin()); + m_NotifyLines.Remove(0); } } @@ -83,11 +83,12 @@ void CTextOverlay::DrawNotify(void) int x = con_notify_invert_x->GetBool() ? g_nWindowRect[0] - con_notify_offset_x->GetInt() : con_notify_offset_x->GetInt(); int y = con_notify_invert_y->GetBool() ? g_nWindowRect[1] - con_notify_offset_y->GetInt() : con_notify_offset_y->GetInt(); - std::lock_guard l(m_Mutex); - for (size_t i = 0, j = m_vNotifyText.size(); i < j; i++) + AUTO_LOCK(m_Mutex); + + for (int i = 0, j = m_NotifyLines.Count(); i < j; i++) { - const CTextNotify& notify = m_vNotifyText[i]; - Color c = GetLogColorForType(notify.m_type); + const CTextNotify& notify = m_NotifyLines[i]; + Color c = GetLogColorForType(notify.m_Type); const float flTimeleft = notify.m_flLifeRemaining; @@ -106,7 +107,7 @@ void CTextOverlay::DrawNotify(void) c[3] = 255; } CMatSystemSurface_DrawColoredText(g_pMatSystemSurface, v_Rui_GetFontFace(), - m_nFontHeight, x, y, c.r(), c.g(), c.b(), c.a(), "%s", notify.m_svMessage.c_str()); + m_nFontHeight, x, y, c.r(), c.g(), c.b(), c.a(), "%s", notify.m_Text.String()); if (IsX360()) { @@ -151,26 +152,24 @@ void CTextOverlay::ShouldDraw(const float flFrameTime) { if (con_drawnotify->GetBool()) { - std::lock_guard l(m_Mutex); + AUTO_LOCK(m_Mutex); - ssize_t i; - ssize_t c = m_vNotifyText.size(); - for (i = c - 1; i >= 0; i--) + for (int i = m_NotifyLines.Count() - 1; i >= 0; i--) { - CTextNotify* pNotify = &m_vNotifyText[i]; + CTextNotify* pNotify = &m_NotifyLines[i]; pNotify->m_flLifeRemaining -= flFrameTime; if (pNotify->m_flLifeRemaining <= 0.0f) { - m_vNotifyText.erase(m_vNotifyText.begin() + i); + m_NotifyLines.Remove(i); continue; } } } - else if (!m_vNotifyText.empty()) + else if (!m_NotifyLines.IsEmpty()) { - std::lock_guard l(m_Mutex); - m_vNotifyText.clear(); + AUTO_LOCK(m_Mutex); + m_NotifyLines.Purge(); } } diff --git a/r5dev/vgui/vgui_debugpanel.h b/r5dev/vgui/vgui_debugpanel.h index f600d376..bab1e87f 100644 --- a/r5dev/vgui/vgui_debugpanel.h +++ b/r5dev/vgui/vgui_debugpanel.h @@ -4,15 +4,15 @@ struct CTextNotify { - CTextNotify(const eDLL_T type, const float nTime, const string& svMessage) + CTextNotify(const eDLL_T type, const float flTime, const char* pszText) { - this->m_svMessage = svMessage; - this->m_flLifeRemaining = nTime; - this->m_type = type; + this->m_Text = pszText; + this->m_flLifeRemaining = flTime; + this->m_Type = type; } - eDLL_T m_type = eDLL_T::NONE; - float m_flLifeRemaining = 0.0f; - string m_svMessage = ""; + eDLL_T m_Type; + float m_flLifeRemaining; + CUtlString m_Text; }; class CTextOverlay @@ -26,7 +26,7 @@ public: } void Update(void); - void AddLog(const eDLL_T context, const string& svText); + void AddLog(const eDLL_T context, const char* pszText); void DrawNotify(void); void DrawFormat(const int x, const int y, const Color c, const char* pszFormat, ...) const; void ShouldDraw(const float flFrameTime); @@ -39,10 +39,10 @@ public: private: Color GetLogColorForType(const eDLL_T type) const; - vector m_vNotifyText; + CUtlVector m_NotifyLines; int m_nFontHeight; // Hardcoded to 16 in this engine. - mutable std::mutex m_Mutex; + mutable CThreadFastMutex m_Mutex; public: int m_nCon_NPrintf_Idx;