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 01/14] 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 02/14] 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 03/14] 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 04/14] 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 05/14] 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 06/14] 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 07/14] 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 08/14] 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 09/14] 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 10/14] 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 11/14] 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 12/14] 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 13/14] 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 14/14] 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; }