Netconsole and ConVar improvements

Implemented StringSplit() (split string with a delimiter, and stop splitting after either the last delimiter has been reached, or nMax, so when nMax is 2, then 'SET mat_sky_color 255 255 0 255' gets split into: "SET" "mat_sky_color" "255 255 0 255").

Netconsole now sends ConVar's/ConCommands and values separately with use of StringSplit.

ConVar now uses internal ChangeStringValue (this runs the callback).
This commit is contained in:
Kawe Mazidjatari 2022-07-31 17:07:35 +02:00
parent 7730d72416
commit 5795d15c83
8 changed files with 108 additions and 67 deletions

View File

@ -10,6 +10,7 @@
#include "tier2/socketcreator.h" #include "tier2/socketcreator.h"
#include "protoc/sv_rcon.pb.h" #include "protoc/sv_rcon.pb.h"
#include "protoc/cl_rcon.pb.h" #include "protoc/cl_rcon.pb.h"
#include "public/include/utility.h"
#include "engine/net.h" #include "engine/net.h"
#include "netconsole/netconsole.h" #include "netconsole/netconsole.h"
@ -113,25 +114,25 @@ void CNetCon::UserInput(void)
this->Disconnect(); this->Disconnect();
return; return;
} }
string::size_type nPos = svInput.find(' ');
if (!svInput.empty()
&& nPos > 0
&& nPos < svInput.size()
&& nPos != svInput.size())
{
std::string svSecondArg = svInput.substr(nPos + 1);
std::string svFirstArg = svInput;
svFirstArg = svFirstArg.erase(svFirstArg.find(' '));
if (strcmp(svFirstArg.c_str(), "PASS") == 0) // Auth with RCON server. vector<string> vSubStrings = StringSplit(svInput, ' ', 2);
if (vSubStrings.size() > 1)
{
if (strcmp(vSubStrings[0].c_str(), "PASS") == 0) // Auth with RCON server.
{ {
std::string svSerialized = this->Serialize(svSecondArg, "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); std::string svSerialized = this->Serialize(vSubStrings[1], "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH);
this->Send(svSerialized); this->Send(svSerialized);
} }
else if (strcmp(svFirstArg.c_str(), "SET") == 0) // Set value query. else if (strcmp(vSubStrings[0].c_str(), "SET") == 0) // Set value query.
{ {
std::string svSerialized = this->Serialize(svFirstArg, svSecondArg, cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE); if (vSubStrings.size() > 2)
this->Send(svSerialized); {
printf("%s\n", vSubStrings[1].c_str());
printf("%s\n", vSubStrings[2].c_str());
std::string svSerialized = this->Serialize(vSubStrings[1], vSubStrings[2], cl_rcon::request_t::SERVERDATA_REQUEST_SETVALUE);
this->Send(svSerialized);
}
} }
else // Execute command query. else // Execute command query.
{ {
@ -139,7 +140,7 @@ void CNetCon::UserInput(void)
this->Send(svSerialized); this->Send(svSerialized);
} }
} }
else // Single arg command query. else if (!svInput.empty()) // Single arg command query.
{ {
std::string svSerialized = this->Serialize(svInput.c_str(), "", cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); std::string svSerialized = this->Serialize(svInput.c_str(), "", cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND);
this->Send(svSerialized); this->Send(svSerialized);
@ -147,19 +148,21 @@ void CNetCon::UserInput(void)
} }
else // Setup connection from input. else // Setup connection from input.
{ {
string::size_type nPos = svInput.find(' '); if (!svInput.empty())
if (!svInput.empty()
&& nPos > 0
&& nPos < svInput.size()
&& nPos != svInput.size())
{ {
std::string svInPort = svInput.substr(nPos + 1); string::size_type nPos = svInput.find(' ');
std::string svInAdr = svInput.erase(svInput.find(' ')); if (nPos > 0
&& nPos < svInput.size()
if (!this->Connect(svInAdr, svInPort)) && nPos != svInput.size())
{ {
m_abPromptConnect = true; std::string svInPort = svInput.substr(nPos + 1);
return; std::string svInAdr = svInput.erase(svInput.find(' '));
if (!this->Connect(svInAdr, svInPort))
{
m_abPromptConnect = true;
return;
}
} }
} }
else // Initialize as [127.0.0.1]:37015. else // Initialize as [127.0.0.1]:37015.

View File

@ -41,6 +41,7 @@ bool StringReplace(string& svInput, const string& svFrom, const string& svTo);
string StringReplaceC(const string& svInput, const string& svFrom, const string& svTo); string StringReplaceC(const string& svInput, const string& svFrom, const string& svTo);
string StringEscape(const string& svInput); string StringEscape(const string& svInput);
string StringUnescape(const string& svInput); string StringUnescape(const string& svInput);
vector<string> StringSplit(string svInput, char cDelim, size_t nMax = SIZE_MAX);
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Bytes // Bytes

View File

@ -560,6 +560,34 @@ string StringUnescape(const string& svInput)
return results; return results;
} }
///////////////////////////////////////////////////////////////////////////////
// For splitting a string into substrings by delimiter.
vector<string> StringSplit(string svInput, char cDelim, size_t nMax)
{
string svSubString;
vector<string> vSubStrings;
svInput = svInput + cDelim;
for (size_t i = 0; i < svInput.size(); i++)
{
if (i != (svInput.size() - 1) &&
vSubStrings.size() >= nMax || svInput[i] != cDelim)
{
svSubString += svInput[i];
}
else
{
if (svSubString.size() != 0)
{
vSubStrings.push_back(svSubString);
}
svSubString.clear();
}
}
return vSubStrings;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// For converting a string to an array of bytes. // For converting a string to an array of bytes.
vector<int> StringToBytes(const string& svInput, bool bNullTerminator) vector<int> StringToBytes(const string& svInput, bool bNullTerminator)

View File

@ -19,7 +19,7 @@ public:
template<typename T> template<typename T>
void Free(T* pMem) void Free(T* pMem)
{ {
const int index = 4; const int index = 5;
CallVFunc<void>(index, this, pMem); CallVFunc<void>(index, this, pMem);
} }
}; };

View File

@ -276,7 +276,7 @@ void ConVar::PurgeHostNames(void) const
{ {
if (ConVar* pCVar = g_pCVar->FindVar(pszHostNames[i])) if (ConVar* pCVar = g_pCVar->FindVar(pszHostNames[i]))
{ {
pCVar->ChangeStringValue("0.0.0.0", pCVar->m_Value.m_fValue); pCVar->ChangeStringValue("0.0.0.0");
} }
} }
} }
@ -521,7 +521,6 @@ void ConVar::InternalSetValue(const char* pszValue)
// Only valid for root convars. // Only valid for root convars.
assert(m_pParent == this); assert(m_pParent == this);
float flOldValue = m_Value.m_fValue;
pszNewValue = const_cast<char*>(pszValue); pszNewValue = const_cast<char*>(pszValue);
if (!pszNewValue) if (!pszNewValue)
{ {
@ -551,7 +550,7 @@ void ConVar::InternalSetValue(const char* pszValue)
if (!(m_nFlags & FCVAR_NEVER_AS_STRING)) if (!(m_nFlags & FCVAR_NEVER_AS_STRING))
{ {
ChangeStringValue(pszNewValue, flOldValue); ChangeStringValue(pszNewValue);
} }
} }
@ -573,7 +572,6 @@ void ConVar::InternalSetIntValue(int nValue)
} }
// Redetermine value // Redetermine value
float flOldValue = m_Value.m_fValue;
m_Value.m_fValue = fValue; m_Value.m_fValue = fValue;
m_Value.m_nValue = nValue; m_Value.m_nValue = nValue;
@ -581,7 +579,7 @@ void ConVar::InternalSetIntValue(int nValue)
{ {
char szTempVal[32]; char szTempVal[32];
snprintf(szTempVal, sizeof(szTempVal), "%d", nValue); snprintf(szTempVal, sizeof(szTempVal), "%d", nValue);
ChangeStringValue(szTempVal, flOldValue); ChangeStringValue(szTempVal);
} }
} }
@ -600,7 +598,6 @@ void ConVar::InternalSetFloatValue(float flValue)
ClampValue(flValue); ClampValue(flValue);
// Redetermine value // Redetermine value
float flOldValue = m_Value.m_fValue;
m_Value.m_fValue = flValue; m_Value.m_fValue = flValue;
m_Value.m_nValue = static_cast<int>(flValue); m_Value.m_nValue = static_cast<int>(flValue);
@ -608,7 +605,7 @@ void ConVar::InternalSetFloatValue(float flValue)
{ {
char szTempVal[32]; char szTempVal[32];
snprintf(szTempVal, sizeof(szTempVal), "%f", flValue); snprintf(szTempVal, sizeof(szTempVal), "%f", flValue);
ChangeStringValue(szTempVal, flOldValue); ChangeStringValue(szTempVal);
} }
} }
@ -740,43 +737,45 @@ bool ConVar::SetColorFromString(const char* pszValue)
// Purpose: changes the ConVar string value. // Purpose: changes the ConVar string value.
// Input : *pszTempVal - flOldValue // Input : *pszTempVal - flOldValue
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ConVar::ChangeStringValue(const char* pszTempVal, float flOldValue) void ConVar::ChangeStringValue(const char* pszTempVal)
{ {
assert(!(m_nFlags & FCVAR_NEVER_AS_STRING)); ConVar_ChangeStringValue(this, pszTempVal);
char* pszOldValue = reinterpret_cast<char*>(_malloca(m_Value.m_iStringLength)); //assert(!(m_nFlags & FCVAR_NEVER_AS_STRING));
if (pszOldValue != NULL)
{
memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength);
}
if (pszTempVal) //char* pszOldValue = reinterpret_cast<char*>(_malloca(m_Value.m_iStringLength));
{ //if (pszOldValue != nullptr)
size_t len = strlen(pszTempVal) + 1; //{
// memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength);
//}
if (len > m_Value.m_iStringLength) //if (pszTempVal)
{ //{
if (m_Value.m_pszString) // size_t len = strlen(pszTempVal) + 1;
{
MemAllocSingleton()->Free(m_Value.m_pszString);
}
m_Value.m_pszString = MemAllocSingleton()->Alloc<const char>(len); // if (len > m_Value.m_iStringLength)
m_Value.m_iStringLength = len; // {
} // if (m_Value.m_pszString)
else if (!m_Value.m_pszString) // {
{ // MemAllocSingleton()->Free(m_Value.m_pszString);
m_Value.m_pszString = MemAllocSingleton()->Alloc<const char>(len); // }
m_Value.m_iStringLength = len;
}
memcpy(const_cast<char*>(m_Value.m_pszString), pszTempVal, len);
}
else
{
m_Value.m_pszString = NULL;
}
pszOldValue = NULL; // m_Value.m_pszString = MemAllocSingleton()->Alloc<const char>(len);
// m_Value.m_iStringLength = len;
// }
// else if (!m_Value.m_pszString)
// {
// m_Value.m_pszString = MemAllocSingleton()->Alloc<const char>(len);
// m_Value.m_iStringLength = len;
// }
// memmove(const_cast<char*>(m_Value.m_pszString), pszTempVal, len);
//}
//else
//{
// m_Value.m_pszString = nullptr;
//}
//pszOldValue = nullptr;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -61,7 +61,7 @@ public:
void SetCallback(void* pCallback); void SetCallback(void* pCallback);
bool SetColorFromString(const char* pszValue); bool SetColorFromString(const char* pszValue);
void ChangeStringValue(const char* pszTempValue, float flOldValue); void ChangeStringValue(const char* pszTempValue);
void ChangeStringValueUnsafe(const char* pszNewValue); void ChangeStringValueUnsafe(const char* pszNewValue);
bool IsRegistered(void) const; bool IsRegistered(void) const;
@ -104,6 +104,9 @@ inline auto ConVar_SetInfo = p_ConVar_SetInfo.RCast<void* (*)(ConVar* thisptr, i
inline CMemory p_ConVar_Register; inline CMemory p_ConVar_Register;
inline auto ConVar_Register = p_ConVar_Register.RCast<void* (*)(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 auto ConVar_Register = p_ConVar_Register.RCast<void* (*)(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_ChangeStringValue;
inline auto ConVar_ChangeStringValue = p_IConVar_IsFlagSet.RCast<bool (*)(ConVar* pConVar, const char* pszTempVal)>();
inline CMemory g_pConVarVFTable; inline CMemory g_pConVarVFTable;
inline CMemory g_pIConVarVFTable; inline CMemory g_pIConVarVFTable;
@ -121,6 +124,7 @@ class VConVar : public IDetour
spdlog::debug("| FUN: IConVar::IsFlagSet : {:#18x} |\n", p_IConVar_IsFlagSet.GetPtr()); spdlog::debug("| FUN: IConVar::IsFlagSet : {:#18x} |\n", p_IConVar_IsFlagSet.GetPtr());
spdlog::debug("| FUN: IConVar::SetInfo : {:#18x} |\n", p_ConVar_SetInfo.GetPtr()); spdlog::debug("| FUN: IConVar::SetInfo : {:#18x} |\n", p_ConVar_SetInfo.GetPtr());
spdlog::debug("| FUN: IConVar::Register : {:#18x} |\n", p_ConVar_Register.GetPtr()); spdlog::debug("| FUN: IConVar::Register : {:#18x} |\n", p_ConVar_Register.GetPtr());
spdlog::debug("| FUN: ConVar::ChangeStringValue : {:#18x} |\n", p_ConVar_ChangeStringValue.GetPtr());
spdlog::debug("| VAR: g_pConVarVtable : {:#18x} |\n", g_pConVarVFTable.GetPtr()); spdlog::debug("| VAR: g_pConVarVtable : {:#18x} |\n", g_pConVarVFTable.GetPtr());
spdlog::debug("| VAR: g_pIConVarVtable : {:#18x} |\n", g_pIConVarVFTable.GetPtr()); spdlog::debug("| VAR: g_pIConVarVtable : {:#18x} |\n", g_pIConVarVFTable.GetPtr());
spdlog::debug("+----------------------------------------------------------------+\n"); spdlog::debug("+----------------------------------------------------------------+\n");
@ -134,10 +138,12 @@ class VConVar : public IDetour
#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) #elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
p_ConVar_Register = g_mGameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x40\xF3\x0F\x10\x84\x24\x00\x00\x00\x00"), "xxxx?xxxx?xxxx?xxxxxxxxxx????"); p_ConVar_Register = g_mGameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x40\xF3\x0F\x10\x84\x24\x00\x00\x00\x00"), "xxxx?xxxx?xxxx?xxxxxxxxxx????");
#endif #endif
p_ConVar_ChangeStringValue = g_mGameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x40\x55\x41\x56\x41\x57\x48\x83\xEC\x30\x48\x8D\x6C\x24\x00\x4C\x8B\x41\x60"), "xxxxxxxxxxxxxx?xxxx");
IConVar_IsFlagSet = p_IConVar_IsFlagSet.RCast<bool (*)(ConVar*, int)>(); /*48 8B 41 48 85 50 38*/ IConVar_IsFlagSet = p_IConVar_IsFlagSet.RCast<bool (*)(ConVar*, int)>(); /*48 8B 41 48 85 50 38*/
ConVar_SetInfo = p_ConVar_SetInfo.RCast<void* (*)(ConVar*, int, int, int, void*)>(); /*40 53 48 83 EC 60 48 8B D9 C6 41 10 00 33 C9 48 8D 05 ? ? ? ? 48 89 4C 24 ? 0F 57 C0 48 89 4C 24 ? 48 89 03 48 8D 05 ? ? ? ? 48 89 43 40*/ ConVar_SetInfo = p_ConVar_SetInfo.RCast<void* (*)(ConVar*, int, int, int, void*)>(); /*40 53 48 83 EC 60 48 8B D9 C6 41 10 00 33 C9 48 8D 05 ? ? ? ? 48 89 4C 24 ? 0F 57 C0 48 89 4C 24 ? 48 89 03 48 8D 05 ? ? ? ? 48 89 43 40*/
ConVar_Register = p_ConVar_Register.RCast<void* (*)(ConVar*, const char*, const char*, int, const char*, bool, float, bool, float, FnChangeCallback_t, const char*)>(); /*48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 40 F3 0F 10 84 24 ? ? ? ?*/ ConVar_Register = p_ConVar_Register.RCast<void* (*)(ConVar*, const char*, const char*, int, const char*, bool, float, bool, float, FnChangeCallback_t, const char*)>(); /*48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 40 F3 0F 10 84 24 ? ? ? ?*/
ConVar_ChangeStringValue = p_IConVar_IsFlagSet.RCast<bool (*)(ConVar*, const char*)>(); /*40 55 41 56 41 57 48 83 EC 30 48 8D 6C 24 ? 4C 8B 41 60*/
} }
virtual void GetVar(void) const virtual void GetVar(void) const
{ {

View File

@ -51,6 +51,7 @@
<ClInclude Include="..\netconsole\netconsole.h" /> <ClInclude Include="..\netconsole\netconsole.h" />
<ClInclude Include="..\protoc\cl_rcon.pb.h" /> <ClInclude Include="..\protoc\cl_rcon.pb.h" />
<ClInclude Include="..\protoc\sv_rcon.pb.h" /> <ClInclude Include="..\protoc\sv_rcon.pb.h" />
<ClInclude Include="..\public\include\utility.h" />
<ClInclude Include="..\tier1\NetAdr2.h" /> <ClInclude Include="..\tier1\NetAdr2.h" />
<ClInclude Include="..\tier2\socketcreator.h" /> <ClInclude Include="..\tier2\socketcreator.h" />
</ItemGroup> </ItemGroup>

View File

@ -81,5 +81,8 @@
<ClInclude Include="..\protoc\cl_rcon.pb.h"> <ClInclude Include="..\protoc\cl_rcon.pb.h">
<Filter>thirdparty\protobuf</Filter> <Filter>thirdparty\protobuf</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\public\include\utility.h">
<Filter>sdk\public</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>