diff --git a/r5dev/common/callback.cpp b/r5dev/common/callback.cpp index 87229496..fa70fa75 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())); @@ -989,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/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/engine/client/cl_rcon.cpp b/r5dev/engine/client/cl_rcon.cpp index a6a5e93a..8f2dabd4 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); } } } @@ -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/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 { } diff --git a/r5dev/engine/server/sv_rcon.cpp b/r5dev/engine/server/sv_rcon.cpp index 46a2ea0f..25a63cb9 100644 --- a/r5dev/engine/server/sv_rcon.cpp +++ b/r5dev/engine/server/sv_rcon.cpp @@ -90,15 +90,15 @@ 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--) { 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--) { - CConnectedNetConsoleData* pData = m_Socket.GetAcceptedSocketData(i); + const CConnectedNetConsoleData& data = m_Socket.GetAcceptedSocketData(i); - if (pData->m_bAuthorized) + 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,14 +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(); } - SendEncode(pData->m_hSocket, s_AuthMessage, sv_rcon_sendlogs->GetString(), + const char* pSendLogs = (!sv_rcon_sendlogs->GetBool() || data.m_bInputOnly) ? "0" : "1"; + + SendEncode(data.m_hSocket, s_AuthMessage, pSendLogs, sv_rcon::response_t::SERVERDATA_RESPONSE_AUTH, static_cast(eDLL_T::NETCON)); } else // Bad password. @@ -345,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++; } } } @@ -385,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)) @@ -394,45 +396,38 @@ 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, false); - } - break; - } - case cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE: - { - if (pData->m_bAuthorized) - { - Execute(request, true); + Execute(request); } break; } case cl_rcon::request_t::SERVERDATA_REQUEST_SEND_CONSOLE_LOG: { - if (pData->m_bAuthorized) + if (data.m_bAuthorized) { - sv_rcon_sendlogs->SetValue(request.requestval().c_str()); + // "0" means the netconsole is input only. + data.m_bInputOnly = !atoi(request.requestval().c_str()); } break; } @@ -446,33 +441,44 @@ bool CRConServer::ProcessMessage(const char* pMsgBuf, const int nMsgLen) } //----------------------------------------------------------------------------- -// Purpose: execute commands issued from netconsole -// Input : *request - -// bConVar - +// Purpose: execute commands issued from netconsole (ignores all protection flags) +// Input : &request - //----------------------------------------------------------------------------- -void CRConServer::Execute(const cl_rcon::request& request, const bool bConVar) const +void CRConServer::Execute(const cl_rcon::request& request) const { - if (bConVar) + const char* pCommandString = request.requestmsg().c_str(); + ConCommandBase* pCommandBase = g_pCVar->FindCommandBase(pCommandString); + + if (!pCommandBase) { - ConVar* pConVar = g_pCVar->FindVar(request.requestmsg().c_str()); - if (pConVar) // Only run if this is a ConVar. - { - 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); } } //----------------------------------------------------------------------------- // 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; } @@ -503,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()) @@ -512,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; } @@ -545,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); @@ -570,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 35222c3e..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 bConVar) const; - bool CheckForBan(CConnectedNetConsoleData* pData); + void Execute(const cl_rcon::request& request) const; + 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 6cc21764..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 - @@ -69,23 +145,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) { - 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(data.m_hSocket, szRecvBuf, sizeof(char), MSG_PEEK); if (nPendingLen == SOCKET_ERROR && m_Socket.IsSocketBlocking()) { return; @@ -95,10 +164,15 @@ 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. - int iResult = ::ioctlsocket(pData->m_hSocket, FIONREAD, reinterpret_cast(&nReadLen)); + int iResult = ::ioctlsocket(data.m_hSocket, FIONREAD, reinterpret_cast(&nReadLen)); if (iResult == SOCKET_ERROR) { @@ -108,10 +182,10 @@ 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 unexpectedly"); + Disconnect("socket closed"); break; } if (nRecvLen < 0 && !m_Socket.IsSocketBlocking()) @@ -121,83 +195,8 @@ 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; } - -//----------------------------------------------------------------------------- -// Purpose: parses input response buffer using length-prefix framing -// Input : *pRecvBuf - -// nRecvLen - -// *pData - -// Output: true on success, false otherwise -//----------------------------------------------------------------------------- -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_nPayloadRead < pData->m_nPayloadLen) - { - pData->m_RecvBuffer[pData->m_nPayloadRead++] = *pRecvBuf; - - pRecvBuf++; - nRecvLen--; - } - if (pData->m_nPayloadRead == pData->m_nPayloadLen) - { - if (!ProcessMessage( - reinterpret_cast(pData->m_RecvBuffer.data()), pData->m_nPayloadLen) - && bSuccess) - { - bSuccess = false; - } - - pData->m_nPayloadLen = 0; - pData->m_nPayloadRead = 0; - } - } - else if (pData->m_nPayloadRead+1 <= sizeof(int)) // Read size field. - { - 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; - - if (!pData->m_bAuthorized && nMaxLen > -1) - { - 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()) - { - 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); - } - } - } - - return bSuccess; -} diff --git a/r5dev/engine/shared/base_rcon.h b/r5dev/engine/shared/base_rcon.h index 35283ac4..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* 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& 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; } 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..6e843210 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -26,6 +26,10 @@ 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, ""); } //----------------------------------------------------------------------------- @@ -39,7 +43,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; @@ -54,7 +58,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]() @@ -99,13 +103,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); } //----------------------------------------------------------------------------- @@ -122,38 +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; } - 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 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(), "", + bSend = Serialize(vecMsg, cmd.Arg(0), cmd.GetCommandString(), cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); } } @@ -172,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; @@ -226,7 +218,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) @@ -291,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); @@ -368,7 +360,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 45a1bb01..2a0926a6 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" @@ -16,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); @@ -42,6 +43,8 @@ private: bool m_bPromptConnect; float m_flTickInterval; + characterset_t m_CharacterSet; + std::string m_Input; mutable std::mutex m_Mutex; }; 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/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/public/tier2/socketcreator.h b/r5dev/public/tier2/socketcreator.h index 91480d10..1520bd3e 100644 --- a/r5dev/public/tier2/socketcreator.h +++ b/r5dev/public/tier2/socketcreator.h @@ -35,26 +35,26 @@ 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; +private: + CUtlVector m_AcceptedSockets; SocketHandle_t m_hListenSocket; // Used to accept connections. -private: enum { SOCKET_TCP_MAX_ACCEPTS = 2 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 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/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; } 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