Add support for listening to, blocking, changing, and faking ClientCommandKeyValues.

This commit is contained in:
Nicholas Hastings
2015-07-12 13:14:46 -04:00
parent 705b5d3f5f
commit c85cc5cbf7
7 changed files with 239 additions and 11 deletions
+88 -1
View File
@@ -2,7 +2,7 @@
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* Copyright (C) 2004-2015 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
@@ -46,6 +46,7 @@
#include "ConsoleDetours.h"
#include "logic_bridge.h"
#include <sourcemod_version.h>
#include "smn_keyvalues.h"
PlayerManager g_Players;
bool g_OnMapStarted = false;
@@ -76,6 +77,9 @@ SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *)
#endif
SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
#endif // SE_DOTA
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
SH_DECL_HOOK2_void(IServerGameClients, ClientCommandKeyValues, SH_NOATTRIB, 0, edict_t *, KeyValues *);
#endif
#if SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK0_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0);
@@ -136,6 +140,7 @@ PlayerManager::PlayerManager()
m_SourceTVUserId = -1;
m_ReplayUserId = -1;
m_bInCCKVHook = false;
m_bAuthstringValidation = true; // use steam auth by default
m_UserIdLookUp = new int[USHRT_MAX+1];
@@ -171,6 +176,10 @@ void PlayerManager::OnSourceModAllInitialized()
SH_ADD_HOOK(IServerGameClients, ClientDisconnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientDisconnect), false);
SH_ADD_HOOK(IServerGameClients, ClientDisconnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientDisconnect_Post), true);
SH_ADD_HOOK(IServerGameClients, ClientCommand, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommand), false);
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
SH_ADD_HOOK(IServerGameClients, ClientCommandKeyValues, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommandKeyValues), false);
SH_ADD_HOOK(IServerGameClients, ClientCommandKeyValues, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommandKeyValues_Post), true);
#endif
SH_ADD_HOOK(IServerGameClients, ClientSettingsChanged, serverClients, SH_MEMBER(this, &PlayerManager::OnClientSettingsChanged), true);
SH_ADD_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_MEMBER(this, &PlayerManager::OnServerActivate), true);
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
@@ -190,6 +199,8 @@ void PlayerManager::OnSourceModAllInitialized()
m_cldisconnect = forwardsys->CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
m_cldisconnect_post = forwardsys->CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
m_clcommand = forwardsys->CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
m_clcommandkv = forwardsys->CreateForward("OnClientCommandKeyValues", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
m_clcommandkv_post = forwardsys->CreateForward("OnClientCommandKeyValues_Post", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
m_clinfochanged = forwardsys->CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
m_clauth = forwardsys->CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
m_onActivate = forwardsys->CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
@@ -218,6 +229,10 @@ void PlayerManager::OnSourceModShutdown()
SH_REMOVE_HOOK(IServerGameClients, ClientDisconnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientDisconnect), false);
SH_REMOVE_HOOK(IServerGameClients, ClientDisconnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientDisconnect_Post), true);
SH_REMOVE_HOOK(IServerGameClients, ClientCommand, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommand), false);
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
SH_REMOVE_HOOK(IServerGameClients, ClientCommandKeyValues, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommandKeyValues), false);
SH_REMOVE_HOOK(IServerGameClients, ClientCommandKeyValues, serverClients, SH_MEMBER(this, &PlayerManager::OnClientCommandKeyValues_Post), true);
#endif
SH_REMOVE_HOOK(IServerGameClients, ClientSettingsChanged, serverClients, SH_MEMBER(this, &PlayerManager::OnClientSettingsChanged), true);
SH_REMOVE_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_MEMBER(this, &PlayerManager::OnServerActivate), true);
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
@@ -233,6 +248,8 @@ void PlayerManager::OnSourceModShutdown()
forwardsys->ReleaseForward(m_cldisconnect);
forwardsys->ReleaseForward(m_cldisconnect_post);
forwardsys->ReleaseForward(m_clcommand);
forwardsys->ReleaseForward(m_clcommandkv);
forwardsys->ReleaseForward(m_clcommandkv_post);
forwardsys->ReleaseForward(m_clinfochanged);
forwardsys->ReleaseForward(m_clauth);
forwardsys->ReleaseForward(m_onActivate);
@@ -1219,6 +1236,76 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
}
}
#if SOURCE_ENGINE >= SE_EYE && SOURCE_ENGINE != SE_DOTA
static bool s_LastCCKVAllowed = true;
void PlayerManager::OnClientCommandKeyValues(edict_t *pEntity, KeyValues *pCommand)
{
int client = IndexOfEdict(pEntity);
cell_t res = Pl_Continue;
CPlayer *pPlayer = &m_Players[client];
if (!pPlayer->IsInGame())
{
RETURN_META(MRES_IGNORED);
}
KeyValueStack *pStk = new KeyValueStack;
pStk->pBase = pCommand;
pStk->pCurRoot.push(pStk->pBase);
pStk->m_bDeleteOnDestroy = false;
Handle_t hndl = handlesys->CreateHandle(g_KeyValueType, pStk, g_pCoreIdent, g_pCoreIdent, NULL);
m_bInCCKVHook = true;
m_clcommandkv->PushCell(client);
m_clcommandkv->PushCell(hndl);
m_clcommandkv->Execute(&res);
m_bInCCKVHook = false;
if (res >= Pl_Handled)
{
s_LastCCKVAllowed = false;
RETURN_META(MRES_SUPERCEDE);
}
s_LastCCKVAllowed = true;
RETURN_META(MRES_IGNORED);
}
void PlayerManager::OnClientCommandKeyValues_Post(edict_t *pEntity, KeyValues *pCommand)
{
if (!s_LastCCKVAllowed)
{
return;
}
int client = IndexOfEdict(pEntity);
CPlayer *pPlayer = &m_Players[client];
if (!pPlayer->IsInGame())
{
return;
}
KeyValueStack *pStk = new KeyValueStack;
pStk->pBase = pCommand;
pStk->pCurRoot.push(pStk->pBase);
pStk->m_bDeleteOnDestroy = false;
Handle_t hndl = handlesys->CreateHandle(g_KeyValueType, pStk, g_pCoreIdent, g_pCoreIdent, NULL);
m_bInCCKVHook = true;
m_clcommandkv_post->PushCell(client);
m_clcommandkv_post->PushCell(hndl);
m_clcommandkv_post->Execute();
m_bInCCKVHook = false;
}
#endif
#if SOURCE_ENGINE == SE_DOTA
void PlayerManager::OnClientSettingsChanged(CEntityIndex index)
{