From c0eb6eb75f0678712ecc9a5be94284fba96ca6d3 Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Thu, 3 Mar 2016 02:47:06 +0100 Subject: [PATCH] Add natives to get client ip and connect password The hltv server doesn't provide a nice IPlayerInfo interface to get stuff. Have to grab it and hold on to it while we can! --- AMBuilder | 3 +- extension.h | 1 + forwards.cpp | 33 ++++++++++---------- forwards.h | 2 -- hltvclientwrapper.cpp | 69 +++++++++++++++++++++++++++++++++++++++++ hltvclientwrapper.h | 71 +++++++++++++++++++++++++++++++++++++++++++ natives.cpp | 64 +++++++++++++++++++++++++++++++++----- sourcetv_test.sp | 5 +-- sourcetvmanager.inc | 24 +++++++++++++++ 9 files changed, 243 insertions(+), 29 deletions(-) create mode 100644 hltvclientwrapper.cpp create mode 100644 hltvclientwrapper.h diff --git a/AMBuilder b/AMBuilder index bbfd14f..1f3d327 100644 --- a/AMBuilder +++ b/AMBuilder @@ -8,7 +8,8 @@ sourceFiles = [ 'extension.cpp', 'natives.cpp', 'forwards.cpp', - 'hltvdirectorwrapper.cpp' + 'hltvdirectorwrapper.cpp', + 'hltvclientwrapper.cpp' ] ############### diff --git a/extension.h b/extension.h index 8acd8c9..87db172 100644 --- a/extension.h +++ b/extension.h @@ -41,6 +41,7 @@ #include #include #include "hltvdirectorwrapper.h" +#include "hltvclientwrapper.h" #include "ihltvdirector.h" #include "ihltv.h" #include "iserver.h" diff --git a/forwards.cpp b/forwards.cpp index d9e61b5..e6ce0e4 100644 --- a/forwards.cpp +++ b/forwards.cpp @@ -97,14 +97,18 @@ void CForwardManager::HookServer(IServer *server) return; SH_ADD_MANUALHOOK(CHLTVServer_ConnectClient, server, SH_MEMBER(this, &CForwardManager::OnSpectatorConnect), false); - SH_ADD_MANUALHOOK(CHLTVServer_ConnectClient, server, SH_MEMBER(this, &CForwardManager::OnSpectatorConnect_Post), true); // Hook all already connected clients as well for late loading for (int i = 0; i < server->GetClientCount(); i++) { IClient *client = server->GetClient(i); if (client->IsConnected()) + { HookClient(client); + // Ip and password unknown :( + // Could add more gamedata to fetch it if people really lateload the extension and expect it to work :B + g_HLTVClientManager.GetClient(i + 1)->Initialize("", "", client); + } } } @@ -114,7 +118,6 @@ void CForwardManager::UnhookServer(IServer *server) return; SH_REMOVE_MANUALHOOK(CHLTVServer_ConnectClient, server, SH_MEMBER(this, &CForwardManager::OnSpectatorConnect), false); - SH_REMOVE_MANUALHOOK(CHLTVServer_ConnectClient, server, SH_MEMBER(this, &CForwardManager::OnSpectatorConnect_Post), true); // Unhook all connected clients as well. for (int i = 0; i < server->GetClientCount(); i++) @@ -296,9 +299,9 @@ IClient *CForwardManager::OnSpectatorConnect(netadr_t & address, int nProtocol, cell_t retVal = 1; m_SpectatorPreConnectFwd->Execute(&retVal); + IServer *server = META_IFACEPTR(IServer); if (retVal == 0) { - IServer *server = META_IFACEPTR(IServer); #if SOURCE_ENGINE == SE_CSGO RejectConnection(server, address, rejectReason); #else @@ -307,30 +310,26 @@ IClient *CForwardManager::OnSpectatorConnect(netadr_t & address, int nProtocol, RETURN_META_VALUE(MRES_SUPERCEDE, nullptr); } - pchPassword = passwordBuffer; + // Call the original function. #if SOURCE_ENGINE == SE_CSGO - RETURN_META_VALUE_MNEWPARAMS(MRES_IGNORED, nullptr, CHLTVServer_ConnectClient, (address, nProtocol, iChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie, pSplitPlayerConnectVector, bUnknown, platform, pUnknown, iUnknown)); + IClient *client = SH_MCALL(server, CHLTVServer_ConnectClient)(address, nProtocol, iChallenge, nAuthProtocol, pchName, passwordBuffer, pCookie, cbCookie, pSplitPlayerConnectVector, bUnknown, platform, pUnknown, iUnknown); #else - RETURN_META_VALUE_MNEWPARAMS(MRES_IGNORED, nullptr, CHLTVServer_ConnectClient, (address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, pchPassword, pCookie, cbCookie)); + IClient *client = SH_MCALL(server, CHLTVServer_ConnectClient)(address, nProtocol, iChallenge, iClientChallenge, nAuthProtocol, pchName, passwordBuffer, pCookie, cbCookie); #endif -} -#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) -#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 -{ - IClient *client = META_RESULT_ORIG_RET(IClient *); if (!client) - RETURN_META_VALUE(MRES_IGNORED, nullptr); + RETURN_META_VALUE(MRES_SUPERCEDE, nullptr); HookClient(client); - m_SpectatorConnectedFwd->PushCell(client->GetPlayerSlot()+1); + HLTVClientWrapper *wrapper = g_HLTVClientManager.GetClient(client->GetPlayerSlot() + 1); + wrapper->Initialize(ipString, pchPassword, client); + + m_SpectatorConnectedFwd->PushCell(client->GetPlayerSlot() + 1); m_SpectatorConnectedFwd->Execute(); - RETURN_META_VALUE(MRES_IGNORED, nullptr); + // Don't call the hooked function again, just return its value. + RETURN_META_VALUE(MRES_SUPERCEDE, client); } void CForwardManager::OnSpectatorDisconnect(const char *reason) diff --git a/forwards.h b/forwards.h index e6e029a..6eb51dc 100644 --- a/forwards.h +++ b/forwards.h @@ -72,11 +72,9 @@ private: #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); #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); - IClient *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 void OnSpectatorDisconnect(const char *reason); diff --git a/hltvclientwrapper.cpp b/hltvclientwrapper.cpp new file mode 100644 index 0000000..5da679e --- /dev/null +++ b/hltvclientwrapper.cpp @@ -0,0 +1,69 @@ +#include "hltvclientwrapper.h" + +HLTVClientWrapper::HLTVClientWrapper() +{ + m_Client = nullptr; +} + +void HLTVClientWrapper::Initialize(const char *ip, const char *password, IClient *client) +{ + m_Ip = ip; + m_Password = password; + m_Client = client; +} + +const char *HLTVClientWrapper::Name() +{ + return m_Client->GetClientName(); +} + +const char *HLTVClientWrapper::Ip() +{ + return m_Ip.chars(); +} + +const char *HLTVClientWrapper::Password() +{ + return m_Password.chars(); +} + +bool HLTVClientWrapper::IsConnected() +{ + return m_Client && m_Client->IsConnected(); +} + +IClient *HLTVClientWrapper::BaseClient() +{ + return m_Client; +} + +void HLTVClientWrapper::Kick(const char *reason) +{ + // Go this route due to different IClient::Disconnect signatures in games.. + m_Client->GetServer()->DisconnectClient(m_Client, reason); +} + +HLTVClientWrapper *HLTVClientManager::GetClient(int index) +{ + // Grow the vector with null pointers + // There might have been clients with lower indexes before we were loaded. + if (m_Clients.length() < (size_t)index) + { + int start = m_Clients.length(); + m_Clients.resize(index); + for (int i = start; i < index; i++) + { + m_Clients[i] = nullptr; + } + } + + if (!m_Clients[index - 1]) + { + m_Clients[index - 1] = new HLTVClientWrapper(); + } + + return m_Clients[index - 1]; +} + +// FIXME: ClientManager instance for each hltvserver instance in csgo! +HLTVClientManager g_HLTVClientManager; \ No newline at end of file diff --git a/hltvclientwrapper.h b/hltvclientwrapper.h new file mode 100644 index 0000000..171a143 --- /dev/null +++ b/hltvclientwrapper.h @@ -0,0 +1,71 @@ +/** +* vim: set ts=4 : +* ============================================================================= +* SourceMod SourceTV Manager Extension +* Copyright (C) 2004-2016 AlliedModders LLC. All rights reserved. +* ============================================================================= +* +* This program is free software; you can redistribute it and/or modify it under +* the terms of the GNU General Public License, version 3.0, as published by the +* Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +* details. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see . +* +* As a special exception, AlliedModders LLC gives you permission to link the +* code of this program (as well as its derivative works) to "Half-Life 2," the +* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software +* by the Valve Corporation. You must obey the GNU General Public License in +* all respects for all other code used. Additionally, AlliedModders LLC grants +* this exception to all derivative works. AlliedModders LLC defines further +* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), +* or . +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_HLTVCLIENT_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_HLTVCLIENT_H_ + +#include "extension.h" +#include "amtl/am-string.h" +#include "amtl/am-vector.h" +#include "amtl/am-utility.h" + +class HLTVClientWrapper { +public: + HLTVClientWrapper(); + void Initialize(const char *ip, const char *password, IClient *client); + +public: + const char *Name(); + const char *Ip(); + const char *Password(); + bool IsConnected(); + IClient *BaseClient(); + + void Kick(const char *reason); + +private: + ke::AString m_Ip; + ke::AString m_Password; + IClient *m_Client; +}; + +class HLTVClientManager { + +public: + HLTVClientWrapper *GetClient(int index); + +private: + ke::Vector> m_Clients; +}; + +extern HLTVClientManager g_HLTVClientManager; + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_HLTVCLIENT_H_ \ No newline at end of file diff --git a/natives.cpp b/natives.cpp index 98abb79..13658b0 100644 --- a/natives.cpp +++ b/natives.cpp @@ -544,7 +544,7 @@ static cell_t Native_IsClientConnected(IPluginContext *pContext, const cell_t *p return 0; } - IClient *pClient = hltvserver->GetBaseServer()->GetClient(client - 1); + HLTVClientWrapper *pClient = g_HLTVClientManager.GetClient(client); return pClient->IsConnected(); } @@ -561,14 +561,62 @@ static cell_t Native_GetSpectatorName(IPluginContext *pContext, const cell_t *pa return 0; } - IClient *pClient = hltvserver->GetBaseServer()->GetClient(client - 1); - if (!pClient || !pClient->IsConnected()) + HLTVClientWrapper *pClient = g_HLTVClientManager.GetClient(client); + if (!pClient->IsConnected()) { pContext->ReportError("Client %d is not connected.", client); return 0; } - pContext->StringToLocalUTF8(params[2], static_cast(params[3]), pClient->GetClientName(), NULL); + pContext->StringToLocalUTF8(params[2], static_cast(params[3]), pClient->Name(), NULL); + return 0; +} + +// native SourceTV_GetSpectatorIP(client, String:ip[], maxlen); +static cell_t Native_GetSpectatorIP(IPluginContext *pContext, const cell_t *params) +{ + if (hltvserver == nullptr) + return 0; + + cell_t client = params[1]; + if (client < 1 || client > hltvserver->GetBaseServer()->GetClientCount()) + { + pContext->ReportError("Invalid spectator client index %d.", client); + return 0; + } + + HLTVClientWrapper *pClient = g_HLTVClientManager.GetClient(client); + if (!pClient->IsConnected()) + { + pContext->ReportError("Client %d is not connected.", client); + return 0; + } + + pContext->StringToLocalUTF8(params[2], static_cast(params[3]), pClient->Ip(), NULL); + return 0; +} + +// native SourceTV_GetSpectatorPassword(client, String:password[], maxlen); +static cell_t Native_GetSpectatorPassword(IPluginContext *pContext, const cell_t *params) +{ + if (hltvserver == nullptr) + return 0; + + cell_t client = params[1]; + if (client < 1 || client > hltvserver->GetBaseServer()->GetClientCount()) + { + pContext->ReportError("Invalid spectator client index %d.", client); + return 0; + } + + HLTVClientWrapper *pClient = g_HLTVClientManager.GetClient(client); + if (!pClient->IsConnected()) + { + pContext->ReportError("Client %d is not connected.", client); + return 0; + } + + pContext->StringToLocalUTF8(params[2], static_cast(params[3]), pClient->Password(), NULL); return 0; } @@ -585,8 +633,8 @@ static cell_t Native_KickClient(IPluginContext *pContext, const cell_t *params) return 0; } - IClient *pClient = hltvserver->GetBaseServer()->GetClient(client - 1); - if (!pClient || !pClient->IsConnected()) + HLTVClientWrapper *pClient = g_HLTVClientManager.GetClient(client); + if (!pClient->IsConnected()) { pContext->ReportError("Client %d is not connected.", client); return 0; @@ -595,7 +643,7 @@ static cell_t Native_KickClient(IPluginContext *pContext, const cell_t *params) char *pReason; pContext->LocalToString(params[2], &pReason); - hltvserver->GetBaseServer()->DisconnectClient(pClient, pReason); + pClient->Kick(pReason); return 0; } @@ -626,6 +674,8 @@ const sp_nativeinfo_t sourcetv_natives[] = { "SourceTV_GetClientCount", Native_GetClientCount }, { "SourceTV_IsClientConnected", Native_IsClientConnected }, { "SourceTV_GetSpectatorName", Native_GetSpectatorName }, + { "SourceTV_GetSpectatorIP", Native_GetSpectatorIP }, + { "SourceTV_GetSpectatorPassword", Native_GetSpectatorPassword }, { "SourceTV_KickClient", Native_KickClient }, { NULL, NULL }, }; diff --git a/sourcetv_test.sp b/sourcetv_test.sp index ba98295..d736b8c 100644 --- a/sourcetv_test.sp +++ b/sourcetv_test.sp @@ -141,14 +141,15 @@ public Action:Cmd_GetDelay(client, args) public Action:Cmd_Spectators(client, args) { ReplyToCommand(client, "SourceTV spectator count: %d/%d", SourceTV_GetSpectatorCount(), SourceTV_GetClientCount()); - new String:sName[64]; + new String:sName[64], String:sIP[16]; for (new i=1;i<=SourceTV_GetClientCount();i++) { if (!SourceTV_IsClientConnected(i)) continue; SourceTV_GetSpectatorName(i, sName, sizeof(sName)); - ReplyToCommand(client, "Client %d: %s", i, sName); + SourceTV_GetSpectatorIP(i, sIP, sizeof(sIP)); + ReplyToCommand(client, "Client %d: %s - %s", i, sName, sIP); } return Plugin_Handled; } diff --git a/sourcetvmanager.inc b/sourcetvmanager.inc index 9316bd9..dcf8451 100644 --- a/sourcetvmanager.inc +++ b/sourcetvmanager.inc @@ -287,6 +287,30 @@ native bool:SourceTV_IsClientConnected(client); */ native SourceTV_GetSpectatorName(client, String:name[], maxlen); +/** + * Get the IP of a SourceTV spectator client. + * + * @param client The spectator client index. + * @param name Buffer for the client ip. + * @param maxlen Maximal length of the buffer. + * @noreturn + * @error Invalid client index or not connected. + */ +native SourceTV_GetSpectatorIP(client, String:ip[], maxlen); + +/** + * Get the password of a SourceTV spectator client. + * The password the client tried to connect with. + * Ignores changes from the SourceTV_OnSpectatorPreConnect forward. + * + * @param client The spectator client index. + * @param name Buffer for the client ip. + * @param maxlen Maximal length of the buffer. + * @noreturn + * @error Invalid client index or not connected. + */ +native SourceTV_GetSpectatorPassword(client, String:password[], maxlen); + /** * Kick a SourceTV spectator client. *