From 5795d15c83016d0c341ce52445f5cda80793cf73 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sun, 31 Jul 2022 17:07:35 +0200 Subject: [PATCH] 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). --- r5dev/netconsole/netconsole.cpp | 55 ++++++++++--------- r5dev/public/include/utility.h | 1 + r5dev/public/utility.cpp | 28 ++++++++++ r5dev/tier0/memstd.h | 2 +- r5dev/tier1/IConVar.cpp | 75 +++++++++++++------------- r5dev/tier1/IConVar.h | 10 +++- r5dev/vproj/netconsole.vcxproj | 1 + r5dev/vproj/netconsole.vcxproj.filters | 3 ++ 8 files changed, 108 insertions(+), 67 deletions(-) diff --git a/r5dev/netconsole/netconsole.cpp b/r5dev/netconsole/netconsole.cpp index e35e426c..80769d41 100644 --- a/r5dev/netconsole/netconsole.cpp +++ b/r5dev/netconsole/netconsole.cpp @@ -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 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. diff --git a/r5dev/public/include/utility.h b/r5dev/public/include/utility.h index e2a29220..8d78c67c 100644 --- a/r5dev/public/include/utility.h +++ b/r5dev/public/include/utility.h @@ -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 StringSplit(string svInput, char cDelim, size_t nMax = SIZE_MAX); ///////////////////////////////////////////////////////////////////////////// // Bytes diff --git a/r5dev/public/utility.cpp b/r5dev/public/utility.cpp index 0782aa56..f8441c41 100644 --- a/r5dev/public/utility.cpp +++ b/r5dev/public/utility.cpp @@ -560,6 +560,34 @@ string StringUnescape(const string& svInput) return results; } +/////////////////////////////////////////////////////////////////////////////// +// For splitting a string into substrings by delimiter. +vector StringSplit(string svInput, char cDelim, size_t nMax) +{ + string svSubString; + vector 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 StringToBytes(const string& svInput, bool bNullTerminator) diff --git a/r5dev/tier0/memstd.h b/r5dev/tier0/memstd.h index f433006d..749d6c31 100644 --- a/r5dev/tier0/memstd.h +++ b/r5dev/tier0/memstd.h @@ -19,7 +19,7 @@ public: template void Free(T* pMem) { - const int index = 4; + const int index = 5; CallVFunc(index, this, pMem); } }; diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index e299672d..b3e7c437 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -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(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(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(_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(_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(len); - m_Value.m_iStringLength = len; - } - else if (!m_Value.m_pszString) - { - m_Value.m_pszString = MemAllocSingleton()->Alloc(len); - m_Value.m_iStringLength = len; - } - memcpy(const_cast(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(len); + // m_Value.m_iStringLength = len; + // } + // else if (!m_Value.m_pszString) + // { + // m_Value.m_pszString = MemAllocSingleton()->Alloc(len); + // m_Value.m_iStringLength = len; + // } + // memmove(const_cast(m_Value.m_pszString), pszTempVal, len); + //} + //else + //{ + // m_Value.m_pszString = nullptr; + //} + + //pszOldValue = nullptr; } //----------------------------------------------------------------------------- diff --git a/r5dev/tier1/IConVar.h b/r5dev/tier1/IConVar.h index 1cbb857c..22f0f272 100644 --- a/r5dev/tier1/IConVar.h +++ b/r5dev/tier1/IConVar.h @@ -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(); +inline CMemory p_ConVar_ChangeStringValue; +inline auto ConVar_ChangeStringValue = p_IConVar_IsFlagSet.RCast(); + 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("\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("\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(); /*48 8B 41 48 85 50 38*/ ConVar_SetInfo = p_ConVar_SetInfo.RCast(); /*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(); /*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(); /*40 55 41 56 41 57 48 83 EC 30 48 8D 6C 24 ? 4C 8B 41 60*/ } virtual void GetVar(void) const { diff --git a/r5dev/vproj/netconsole.vcxproj b/r5dev/vproj/netconsole.vcxproj index cdfb30d3..3444bf26 100644 --- a/r5dev/vproj/netconsole.vcxproj +++ b/r5dev/vproj/netconsole.vcxproj @@ -51,6 +51,7 @@ + diff --git a/r5dev/vproj/netconsole.vcxproj.filters b/r5dev/vproj/netconsole.vcxproj.filters index dc8827f9..e5a47942 100644 --- a/r5dev/vproj/netconsole.vcxproj.filters +++ b/r5dev/vproj/netconsole.vcxproj.filters @@ -81,5 +81,8 @@ thirdparty\protobuf + + sdk\public + \ No newline at end of file