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
This commit is contained in:
Peace-Maker 2016-03-03 01:12:16 +01:00
parent 4bb751afaf
commit 10f7fa56a1
4 changed files with 87 additions and 7 deletions

View File

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

View File

@ -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<INetMessage *> &, 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<NetMsg_SplitPlayerConnect *> &, 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<NetMsg_SplitPlayerConnect *> &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<CNetMessagePB<16, CCLCMsg_SplitPlayerConnect, 0, true> *, CUtlMemory<CNetMessagePB<16, CCLCMsg_SplitPlayerConnect, 0, true> *, 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<INetMessage *> &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<NetMsg_SplitPlayerConnect *> &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<INetMessage *> &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<NetMsg_SplitPlayerConnect *> &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

View File

@ -35,6 +35,20 @@
#include "extension.h"
#include "netadr.h"
#if SOURCE_ENGINE == SE_CSGO
#include "netmessages.pb.h"
template <int Type, class NetMessage, int Group, bool reliable>
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<INetMessage *> &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<INetMessage *> &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<NetMsg_SplitPlayerConnect *> &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<NetMsg_SplitPlayerConnect *> &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);

View File

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