1
0
mirror of https://github.com/Mauler125/r5sdk.git synced 2025-02-09 19:15:03 +01:00

Merge pull request from Mauler125/rcon_improvements

Rcon improvements
This commit is contained in:
Kawe Mazidjatari 2023-08-04 17:50:30 +02:00 committed by GitHub
commit ef8173636d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1505 additions and 1448 deletions

@ -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

@ -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

@ -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);

@ -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;

@ -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.
}
};

@ -448,7 +448,7 @@ void DetourRegister() // Register detour classes to be searched and hooked.
// Tier1
REGISTER(VCommandLine);
REGISTER(VConCommand);
REGISTER(VConVar);
REGISTER(VCVar);
// VPC

@ -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<char> 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<char> 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
//-----------------------------------------------------------------------------

@ -21,6 +21,10 @@ public:
bool Serialize(vector<char>& 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);

@ -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<void (*)(ECommandTarget_t, const char*, cmd_source_t)>(); /*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<void (*)(void)>(); /*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<void (*)(ECommandTarget_t, const ConCommandBase*, const CCommand*, bool)>();
v_Cmd_ForwardToServer = p_Cmd_ForwardToServer.RCast<bool (*)(const CCommand*)>(); /*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 { }

@ -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<char>& 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<int>(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<int>(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<int>(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 "<val>".
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<ConVar*>(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);
}

@ -37,13 +37,13 @@ public:
bool Serialize(vector<char>& vecBuf, const char* pResponseMsg, const char* pResponseVal, const sv_rcon::response_t responseType,
const int nMessageId = static_cast<int>(eDLL_T::NETCON), const int nMessageType = static_cast<int>(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);

@ -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<const char*>(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<u_long*>(&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<u_long*>(&nReadLen));
int iResult = ::ioctlsocket(data.m_hSocket, FIONREAD, reinterpret_cast<u_long*>(&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<const char*>(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<u_long*>(&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;
}

@ -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; }

@ -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);
}
//-----------------------------------------------------------------------------

@ -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<std::mutex> 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<string> vSubStrings = StringSplit(m_Input, ' ', 2);
vector<char> 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<string> 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<std::mutex> 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<char> 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;
}

@ -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;
};

@ -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<std::string> request_t_strings[6] = {};
static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed<std::string> 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<request_t>(int_value);
}

@ -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<int32_t>::min(),
request_t_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::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);

@ -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<std::string> response_t_strings[6] = {};
static ::PROTOBUF_NAMESPACE_ID::internal::ExplicitlyConstructed<std::string> 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<response_t>(int_value);
}

@ -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<int32_t>::min(),
response_t_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::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);

@ -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
//-----------------------------------------------------------------------------

@ -1,6 +1,7 @@
#ifndef ICVAR_H
#define ICVAR_H
#include "tier0/annotations.h"
#include "iconvar.h"
#include "appframework/IAppSystem.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<bool (*)(ConCommandBase*, int)>(); /*85 51 38 0F 95 C0 C3*/
ConCommand_AutoCompleteSuggest = p_ConCommand_AutoCompleteSuggest.RCast<bool (*)(ConCommand*, const char*, CUtlVector< CUtlString >&)>();
NullSub = p_NullSub.RCast<void(*)(void)>(); /*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<FnCommandCompletionCallback>(); /*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<ConCommandBase*>();
}
virtual void Attach(void) const { };
virtual void Detach(void) const { };
};
///////////////////////////////////////////////////////////////////////////////
#endif // TIER1_CMD_H

302
r5dev/public/tier1/convar.h Normal file

@ -0,0 +1,302 @@
//===== Copyright <20> 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<FnChangeCallback_t> 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<double>(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<unsigned char*>(&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<uintptr_t>(g_pConCommandBaseVFTable));
LogConAdr("ConCommand::`vftable'", reinterpret_cast<uintptr_t>(g_pConCommandVFTable));
LogConAdr("ConVar::`vbtable'", reinterpret_cast<uintptr_t>(g_pConVarVBTable));
LogConAdr("ConVar::`vftable'", reinterpret_cast<uintptr_t>(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<bool (*)(ConVar*, int)>();
v_ConVar_Register = p_ConVar_Register.RCast<void* (*)(ConVar*, const char*, const char*, int, const char*, bool, float, bool, float, FnChangeCallback_t, const char*)>();
v_ConVar_Unregister = p_ConVar_Unregister.RCast<void (*)(ConVar*)>();
}
virtual void GetVar(void) const { }
virtual void GetCon(void) const
{
g_pConCommandBaseVFTable = g_GameDll.GetVirtualMethodTable(".?AVConCommandBase@@").RCast<ConCommandBase*>();
g_pConCommandVFTable = g_GameDll.GetVirtualMethodTable(".?AVConCommand@@").RCast<ConCommand*>();
g_pConVarVBTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 0).RCast<ConVar*>();
g_pConVarVFTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 1).RCast<IConVar*>();
}
virtual void Attach(void) const { }
virtual void Detach(void) const { }
};
///////////////////////////////////////////////////////////////////////////////
#endif // CONVAR_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<void*> 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<void*> 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<FnChangeCallback_t> 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<double>(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<unsigned char*>(&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 = "<<unspecified>>");
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<uintptr_t>(g_pConCommandVFTable));
LogConAdr("ConVar::`vbtable'", reinterpret_cast<uintptr_t>(g_pConVarVBTable));
LogConAdr("ConVar::`vftable'", reinterpret_cast<uintptr_t>(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<uintptr_t>(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<bool (*)(ConVar*, int)>();
v_ConVar_Register = p_ConVar_Register.RCast<void* (*)(ConVar*, const char*, const char*, int, const char*, bool, float, bool, float, FnChangeCallback_t, const char*)>();
v_ConVar_Unregister = p_ConVar_Unregister.RCast<void (*)(ConVar*)>();
v_ConVar_PrintDescription = p_ConVar_PrintDescription.RCast<void* (*)(ConCommandBase*)>();
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<void* (*)(ConCommandBase*)>();
}
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<CCvar*>();
}
virtual void GetCon(void) const
{
g_pConVarVBTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 0).RCast<ConVar*>();
g_pConVarVFTable = g_GameDll.GetVirtualMethodTable(".?AVConVar@@", 1).RCast<IConVar*>();
}
virtual void GetCon(void) const { }
virtual void Attach(void) const;
virtual void Detach(void) const;
};

@ -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<AcceptedSocket_t> m_hAcceptedSockets;
private:
CUtlVector<AcceptedSocket_t> m_AcceptedSockets;
SocketHandle_t m_hListenSocket; // Used to accept connections.
private:
enum
{
SOCKET_TCP_MAX_ACCEPTS = 2

@ -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

@ -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

@ -22,6 +22,7 @@ add_sources( SOURCE_GROUP "Utility"
add_sources( SOURCE_GROUP "Private"
"cmd.cpp"
"convar.cpp"
"cvar.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;
}

497
r5dev/tier1/convar.cpp Normal file

@ -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<ConVar*>(m_pParent);
pCVar->InternalSetIntValue(nValue);
}
//-----------------------------------------------------------------------------
// Purpose: sets the ConVar float value.
// Input : flValue -
//-----------------------------------------------------------------------------
void ConVar::SetValue(float flValue)
{
ConVar* pCVar = reinterpret_cast<ConVar*>(m_pParent);
pCVar->InternalSetFloatValue(flValue);
}
//-----------------------------------------------------------------------------
// Purpose: sets the ConVar string value.
// Input : *szValue -
//-----------------------------------------------------------------------------
void ConVar::SetValue(const char* pszValue)
{
ConVar* pCVar = reinterpret_cast<ConVar*>(m_pParent);
pCVar->InternalSetValue(pszValue);
}
//-----------------------------------------------------------------------------
// Purpose: sets the ConVar color value.
// Input : value -
//-----------------------------------------------------------------------------
void ConVar::SetValue(Color value)
{
ConVar* pCVar = reinterpret_cast<ConVar*>(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<unsigned char*>(&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<unsigned char*>(&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<float>(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<void*>(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);
}

@ -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<ConVar*>(m_pParent);
pCVar->InternalSetIntValue(nValue);
}
//-----------------------------------------------------------------------------
// Purpose: sets the ConVar float value.
// Input : flValue -
//-----------------------------------------------------------------------------
void ConVar::SetValue(float flValue)
{
ConVar* pCVar = reinterpret_cast<ConVar*>(m_pParent);
pCVar->InternalSetFloatValue(flValue);
}
//-----------------------------------------------------------------------------
// Purpose: sets the ConVar string value.
// Input : *szValue -
//-----------------------------------------------------------------------------
void ConVar::SetValue(const char* pszValue)
{
ConVar* pCVar = reinterpret_cast<ConVar*>(m_pParent);
pCVar->InternalSetValue(pszValue);
}
//-----------------------------------------------------------------------------
// Purpose: sets the ConVar color value.
// Input : value -
//-----------------------------------------------------------------------------
void ConVar::SetValue(Color value)
{
ConVar* pCVar = reinterpret_cast<ConVar*>(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<unsigned char*>(&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<unsigned char*>(&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<float>(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<void*>(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
{

@ -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<int>(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<int>(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;
}

@ -6,6 +6,7 @@ start_sources()
add_sources( SOURCE_GROUP "Private"
"autocompletefilelist.cpp"
"autocompletefilelist.h"
"concommandhash.cpp"
"concommandhash.h"
"keyvaluessystem.cpp"
"keyvaluessystem.h"

@ -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

@ -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