From 10f7fa56a1ebef41f4c5a407999b839717db6507 Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Thu, 3 Mar 2016 01:12:16 +0100 Subject: [PATCH] Extract player name in ConnectClient hook in CS:GO CS:GO doesn't send the client name in plain text, but wraps it in some protobuf construct. Parse that list of client convars for the player name and use it in the SourceTV_OnSpectatorPreConnect forward --- AMBuilder | 35 ++++++++++++++++++++++++++++++++++- forwards.cpp | 39 ++++++++++++++++++++++++++++++++++++--- forwards.h | 18 ++++++++++++++++-- sourcetvmanager.inc | 2 +- 4 files changed, 87 insertions(+), 7 deletions(-) diff --git a/AMBuilder b/AMBuilder index cc1c170..bbfd14f 100644 --- a/AMBuilder +++ b/AMBuilder @@ -7,7 +7,8 @@ projectName = 'sourcetvmanager' sourceFiles = [ 'extension.cpp', 'natives.cpp', - 'forwards.cpp' + 'forwards.cpp', + 'hltvdirectorwrapper.cpp' ] ############### @@ -31,5 +32,37 @@ for sdk_name in ['css', 'csgo']: sdk = Extension.sdks[sdk_name] binary = Extension.HL2Config(project, projectName + '.ext.' + sdk.ext, sdk) + compiler = binary.compiler + + if sdk.name == 'csgo': + compiler.cxxincludes += [ + os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'), + os.path.join(sdk.path, 'public', 'engine', 'protobuf'), + os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf') + ] + + if builder.target_platform == 'linux': + lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a') + elif builder.target_platform == 'mac': + lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a') + elif builder.target_platform == 'windows': + msvc_ver = compiler.version + vs_year = '' + if msvc_ver == 1800: + vs_year = '2013' + else: + raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"') + + if 'DEBUG' in compiler.defines: + lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib') + else: + lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib') + compiler.linkflags.insert(0, binary.Dep(lib_path)) + + binary.sources += [ + os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'), + os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'), + os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'), + ] Extension.extensions = builder.Add(project) diff --git a/forwards.cpp b/forwards.cpp index c9e8ec7..d9e61b5 100644 --- a/forwards.cpp +++ b/forwards.cpp @@ -42,7 +42,7 @@ SH_DECL_HOOK0_void(IDemoRecorder, StopRecording, SH_NOATTRIB, 0) #endif #if SOURCE_ENGINE == SE_CSGO -SH_DECL_MANUALHOOK13(CHLTVServer_ConnectClient, 0, 0, 0, IClient *, netadr_s &, int, int, int, const char *, const char *, const char *, int, CUtlVector &, bool, CrossPlayPlatform_t, const unsigned char *, int); +SH_DECL_MANUALHOOK13(CHLTVServer_ConnectClient, 0, 0, 0, IClient *, netadr_s &, int, int, int, const char *, const char *, const char *, int, CUtlVector &, bool, CrossPlayPlatform_t, const unsigned char *, int); SH_DECL_HOOK1_void(IClient, Disconnect, SH_NOATTRIB, 0, const char *); #else SH_DECL_MANUALHOOK9(CHLTVServer_ConnectClient, 0, 0, 0, IClient *, netadr_t &, int, int, int, int, const char *, const char *, const char *, int); @@ -188,6 +188,31 @@ static void RejectConnection(IServer *server, netadr_t &address, char *pchReason pRejectConnection->Execute(vstk, NULL); } } + +static bool ExtractPlayerName(CUtlVector &pSplitPlayerConnectVector, char *name, int maxlen) +{ + for (int i = 0; i < pSplitPlayerConnectVector.Count(); i++) + { + NetMsg_SplitPlayerConnect *split = pSplitPlayerConnectVector[i]; + if (!split->has_convars()) + continue; + + const CMsg_CVars cvars = split->convars(); + for (int c = 0; c < cvars.cvars_size(); c++) + { + const CMsg_CVars_CVar cvar = cvars.cvars(c); + if (!cvar.has_name() || !cvar.has_value()) + continue; + + if (!strcmp(cvar.name().c_str(), "name")) + { + strncpy(name, cvar.value().c_str(), maxlen); + return true; + } + } + } + return false; +} #else static void RejectConnection(IServer *server, netadr_t &address, int iClientChallenge, char *pchReason) { @@ -239,7 +264,7 @@ static void RejectConnection(IServer *server, netadr_t &address, int iClientChal char passwordBuffer[255]; #if SOURCE_ENGINE == SE_CSGO // CHLTVServer::ConnectClient(ns_address const&, int, int, int, char const*, char const*, char const*, int, CUtlVector *, CUtlMemory *, int>> &, bool, CrossPlayPlatform_t, unsigned char const*, int) -IClient *CForwardManager::OnSpectatorConnect(netadr_s & address, int nProtocol, int iChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie, CUtlVector &pSplitPlayerConnectVector, bool bUnknown, CrossPlayPlatform_t platform, const unsigned char *pUnknown, int iUnknown) +IClient *CForwardManager::OnSpectatorConnect(netadr_s & address, int nProtocol, int iChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie, CUtlVector &pSplitPlayerConnectVector, bool bUnknown, CrossPlayPlatform_t platform, const unsigned char *pUnknown, int iUnknown) #else IClient *CForwardManager::OnSpectatorConnect(netadr_t & address, int nProtocol, int iChallenge, int iClientChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie) #endif @@ -247,6 +272,14 @@ IClient *CForwardManager::OnSpectatorConnect(netadr_t & address, int nProtocol, if (!pCookie || cbCookie < sizeof(uint64)) RETURN_META_VALUE(MRES_IGNORED, nullptr); +#if SOURCE_ENGINE == SE_CSGO + // CS:GO doesn't send the player name in pchName, but only in the client info convars. + // Try to extract the name from the protobuf msg. + char playerName[MAX_PLAYER_NAME_LENGTH]; + if (ExtractPlayerName(pSplitPlayerConnectVector, playerName, sizeof(playerName))) + pchName = playerName; +#endif + char ipString[16]; V_snprintf(ipString, sizeof(ipString), "%u.%u.%u.%u", address.ip[0], address.ip[1], address.ip[2], address.ip[3]); V_strncpy(passwordBuffer, pchPassword, 255); @@ -283,7 +316,7 @@ IClient *CForwardManager::OnSpectatorConnect(netadr_t & address, int nProtocol, } #if SOURCE_ENGINE == SE_CSGO -IClient *CForwardManager::OnSpectatorConnect_Post(netadr_s & address, int nProtocol, int iChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie, CUtlVector &pSplitPlayerConnectVector, bool bUnknown, CrossPlayPlatform_t platform, const unsigned char * pUnknown, int iUnknown) +IClient *CForwardManager::OnSpectatorConnect_Post(netadr_s & address, int nProtocol, int iChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie, CUtlVector &pSplitPlayerConnectVector, bool bUnknown, CrossPlayPlatform_t platform, const unsigned char * pUnknown, int iUnknown) #else IClient *CForwardManager::OnSpectatorConnect_Post(netadr_t & address, int nProtocol, int iChallenge, int iClientChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie) #endif diff --git a/forwards.h b/forwards.h index 6f7c0a6..e6e029a 100644 --- a/forwards.h +++ b/forwards.h @@ -35,6 +35,20 @@ #include "extension.h" #include "netadr.h" +#if SOURCE_ENGINE == SE_CSGO +#include "netmessages.pb.h" + +template +class CNetMessagePB : public INetMessage, public NetMessage { +public: + ~CNetMessagePB() {} + +}; + +typedef CNetMessagePB<16, CCLCMsg_SplitPlayerConnect, 0, true> NetMsg_SplitPlayerConnect; + +#endif + class CGameInfo; class CForwardManager @@ -57,8 +71,8 @@ private: void OnStartRecording_Post(const char *filename, bool bContinuously); #if SOURCE_ENGINE == SE_CSGO void OnStopRecording_Post(CGameInfo const *info); - IClient *OnSpectatorConnect(netadr_s & address, int nProtocol, int iChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie, CUtlVector &pSplitPlayerConnectVector, bool bUnknown, CrossPlayPlatform_t platform, const unsigned char *pUnknown, int iUnknown); - IClient *OnSpectatorConnect_Post(netadr_s & address, int nProtocol, int iChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie, CUtlVector &pSplitPlayerConnectVector, bool bUnknown, CrossPlayPlatform_t platform, const unsigned char *pUnknown, int iUnknown); + IClient *OnSpectatorConnect(netadr_s & address, int nProtocol, int iChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie, CUtlVector &pSplitPlayerConnectVector, bool bUnknown, CrossPlayPlatform_t platform, const unsigned char *pUnknown, int iUnknown); + IClient *OnSpectatorConnect_Post(netadr_s & address, int nProtocol, int iChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie, CUtlVector &pSplitPlayerConnectVector, bool bUnknown, CrossPlayPlatform_t platform, const unsigned char *pUnknown, int iUnknown); #else void OnStopRecording_Post(); IClient *OnSpectatorConnect(netadr_t &address, int nProtocol, int iChallenge, int iClientChallenge, int nAuthProtocol, const char *pchName, const char *pchPassword, const char *pCookie, int cbCookie); diff --git a/sourcetvmanager.inc b/sourcetvmanager.inc index 1919a42..9316bd9 100644 --- a/sourcetvmanager.inc +++ b/sourcetvmanager.inc @@ -303,7 +303,7 @@ native SourceTV_KickClient(client, const String:sReason[]); * This is called before any other validation has happened. * Similar to the OnClientPreConnectEx forward in the Connect extension by asherkin. * - * @param name The player name (always empty in CS:GO). + * @param name The player name. * @param password The password the client used to connect. Can be overwritten. * @param ip The ip address of the client. * @param rejectReason Buffer to write the reject reason to, if you want to reject the client from connecting.