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 "protoc/sv_rcon.pb.h"
#include "protoc/cl_rcon.pb.h"
#include "public/include/utility.h"
#include "engine/net.h"
#include "netconsole/netconsole.h"
@ -113,25 +114,25 @@ void CNetCon::UserInput(void)
this->Disconnect();
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);
}
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);
this->Send(svSerialized);
if (vSubStrings.size() > 2)
{
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.
{
@ -139,7 +140,7 @@ void CNetCon::UserInput(void)
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);
this->Send(svSerialized);
@ -147,19 +148,21 @@ void CNetCon::UserInput(void)
}
else // Setup connection from input.
{
string::size_type nPos = svInput.find(' ');
if (!svInput.empty()
&& nPos > 0
&& nPos < svInput.size()
&& nPos != svInput.size())
if (!svInput.empty())
{
std::string svInPort = svInput.substr(nPos + 1);
std::string svInAdr = svInput.erase(svInput.find(' '));
if (!this->Connect(svInAdr, svInPort))
string::size_type nPos = svInput.find(' ');
if (nPos > 0
&& nPos < svInput.size()
&& nPos != svInput.size())
{
m_abPromptConnect = true;
return;
std::string svInPort = svInput.substr(nPos + 1);
std::string svInAdr = svInput.erase(svInput.find(' '));
if (!this->Connect(svInAdr, svInPort))
{
m_abPromptConnect = true;
return;
}
}
}
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 StringEscape(const string& svInput);
string StringUnescape(const string& svInput);
vector<string> StringSplit(string svInput, char cDelim, size_t nMax = SIZE_MAX);
/////////////////////////////////////////////////////////////////////////////
// Bytes

View File

@ -560,6 +560,34 @@ string StringUnescape(const string& svInput)
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.
vector<int> StringToBytes(const string& svInput, bool bNullTerminator)

View File

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

View File

@ -276,7 +276,7 @@ void ConVar::PurgeHostNames(void) const
{
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.
assert(m_pParent == this);
float flOldValue = m_Value.m_fValue;
pszNewValue = const_cast<char*>(pszValue);
if (!pszNewValue)
{
@ -551,7 +550,7 @@ void ConVar::InternalSetValue(const char* pszValue)
if (!(m_nFlags & FCVAR_NEVER_AS_STRING))
{
ChangeStringValue(pszNewValue, flOldValue);
ChangeStringValue(pszNewValue);
}
}
@ -573,7 +572,6 @@ void ConVar::InternalSetIntValue(int nValue)
}
// Redetermine value
float flOldValue = m_Value.m_fValue;
m_Value.m_fValue = fValue;
m_Value.m_nValue = nValue;
@ -581,7 +579,7 @@ void ConVar::InternalSetIntValue(int nValue)
{
char szTempVal[32];
snprintf(szTempVal, sizeof(szTempVal), "%d", nValue);
ChangeStringValue(szTempVal, flOldValue);
ChangeStringValue(szTempVal);
}
}
@ -600,7 +598,6 @@ void ConVar::InternalSetFloatValue(float flValue)
ClampValue(flValue);
// Redetermine value
float flOldValue = m_Value.m_fValue;
m_Value.m_fValue = flValue;
m_Value.m_nValue = static_cast<int>(flValue);
@ -608,7 +605,7 @@ void ConVar::InternalSetFloatValue(float flValue)
{
char szTempVal[32];
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.
// 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));
if (pszOldValue != NULL)
{
memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength);
}
//assert(!(m_nFlags & FCVAR_NEVER_AS_STRING));
if (pszTempVal)
{
size_t len = strlen(pszTempVal) + 1;
//char* pszOldValue = reinterpret_cast<char*>(_malloca(m_Value.m_iStringLength));
//if (pszOldValue != nullptr)
//{
// memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength);
//}
if (len > m_Value.m_iStringLength)
{
if (m_Value.m_pszString)
{
MemAllocSingleton()->Free(m_Value.m_pszString);
}
//if (pszTempVal)
//{
// size_t len = strlen(pszTempVal) + 1;
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;
}
memcpy(const_cast<char*>(m_Value.m_pszString), pszTempVal, len);
}
else
{
m_Value.m_pszString = NULL;
}
// if (len > m_Value.m_iStringLength)
// {
// if (m_Value.m_pszString)
// {
// MemAllocSingleton()->Free(m_Value.m_pszString);
// }
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);
bool SetColorFromString(const char* pszValue);
void ChangeStringValue(const char* pszTempValue, float flOldValue);
void ChangeStringValue(const char* pszTempValue);
void ChangeStringValueUnsafe(const char* pszNewValue);
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 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_pIConVarVFTable;
@ -121,6 +124,7 @@ class VConVar : public IDetour
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::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_pIConVarVtable : {:#18x} |\n", g_pIConVarVFTable.GetPtr());
spdlog::debug("+----------------------------------------------------------------+\n");
@ -134,10 +138,12 @@ class VConVar : public IDetour
#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????");
#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*/
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_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
{

View File

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

View File

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