Add OnSpectatorChatMessage forwards to catch chat

Messages and chatgroups can be changed or blocked.
This commit is contained in:
Peace-Maker 2016-11-14 01:16:39 -06:00
parent 2c88455744
commit e5db34a3e3
12 changed files with 355 additions and 29 deletions

View File

@ -6,11 +6,14 @@ projectName = 'sourcetvmanager'
# smsdk_ext.cpp will be automatically added later # smsdk_ext.cpp will be automatically added later
sourceFiles = [ sourceFiles = [
'extension.cpp', 'extension.cpp',
'commonhooks.cpp',
'natives.cpp', 'natives.cpp',
'forwards.cpp', 'forwards.cpp',
'hltvserverwrapper.cpp', 'hltvserverwrapper.cpp',
'hltvdirectorwrapper.cpp', 'hltvdirectorwrapper.cpp',
'hltvclientwrapper.cpp' 'hltvclientwrapper.cpp',
os.path.join(Extension.sm_root, 'public', 'CDetour', 'detours.cpp'),
os.path.join(Extension.sm_root, 'public', 'asm', 'asm.c')
] ]
############### ###############
@ -36,12 +39,6 @@ for sdk_name in ['css', 'tf2', 'dods', 'hl2dm', 'csgo']:
binary = Extension.HL2Config(project, projectName + '.ext.' + sdk.ext, sdk) binary = Extension.HL2Config(project, projectName + '.ext.' + sdk.ext, sdk)
compiler = binary.compiler compiler = binary.compiler
if builder.target_platform == 'linux':
binary.sources += [
os.path.join(Extension.sm_root, 'public', 'CDetour', 'detours.cpp'),
os.path.join(Extension.sm_root, 'public', 'asm', 'asm.c')
]
if sdk.name == 'csgo': if sdk.name == 'csgo':
compiler.cxxincludes += [ compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'), os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),

63
commonhooks.cpp Normal file
View File

@ -0,0 +1,63 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include "extension.h"
#include "commonhooks.h"
#include "forwards.h"
#include "hltvserverwrapper.h"
CCommonHooks g_pSTVCommonHooks;
// Declare the hook here so we can use it in hltvserverwrapper to fix crashes with the "status" command and host_client.
// And use it in forwards to hook spectator chat messages.
SH_DECL_HOOK1(IClient, ExecuteStringCommand, SH_NOATTRIB, 0, bool, const char *);
void CCommonHooks::AddSpectatorHook(CForwardManager *fwdmgr, IClient *client)
{
SH_ADD_HOOK(IClient, ExecuteStringCommand, client, SH_MEMBER(fwdmgr, &CForwardManager::OnSpectatorExecuteStringCommand), false);
}
void CCommonHooks::RemoveSpectatorHook(CForwardManager *fwdmgr, IClient *client)
{
SH_REMOVE_HOOK(IClient, ExecuteStringCommand, client, SH_MEMBER(fwdmgr, &CForwardManager::OnSpectatorExecuteStringCommand), false);
}
void CCommonHooks::AddHLTVClientHook(HLTVServerWrapper *wrapper, IClient *client)
{
SH_ADD_HOOK(IClient, ExecuteStringCommand, client, SH_MEMBER(wrapper, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand), false);
SH_ADD_HOOK(IClient, ExecuteStringCommand, client, SH_MEMBER(wrapper, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true);
}
void CCommonHooks::RemoveHLTVClientHook(HLTVServerWrapper *wrapper, IClient *client)
{
SH_REMOVE_HOOK(IClient, ExecuteStringCommand, client, SH_MEMBER(wrapper, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand), false);
SH_REMOVE_HOOK(IClient, ExecuteStringCommand, client, SH_MEMBER(wrapper, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true);
}

52
commonhooks.h Normal file
View File

@ -0,0 +1,52 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_COMMON_HOOKS_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_COMMON_HOOKS_H_
class IClient;
class CForwardManager;
class HLTVServerWrapper;
class CCommonHooks {
public:
// For forwards
void AddSpectatorHook(CForwardManager *fwdmgr, IClient *client);
void RemoveSpectatorHook(CForwardManager *fwdmgr, IClient *client);
// For host_client and status fix
void AddHLTVClientHook(HLTVServerWrapper *wrapper, IClient *client);
void RemoveHLTVClientHook(HLTVServerWrapper *wrapper, IClient *client);
};
extern CCommonHooks g_pSTVCommonHooks;
#endif // _INCLUDE_SOURCEMOD_EXTENSION_COMMON_HOOKS_H_

View File

@ -95,9 +95,7 @@ bool SourceTVManager::SDK_OnLoad(char *error, size_t maxlength, bool late)
g_HLTVServers.InitHooks(); g_HLTVServers.InitHooks();
#ifndef WIN32
CDetourManager::Init(smutils->GetScriptingEngine(), g_pGameConf); CDetourManager::Init(smutils->GetScriptingEngine(), g_pGameConf);
#endif
sharesys->AddNatives(myself, sourcetv_natives); sharesys->AddNatives(myself, sourcetv_natives);
sharesys->RegisterLibrary(myself, "sourcetvmanager"); sharesys->RegisterLibrary(myself, "sourcetvmanager");

View File

@ -40,9 +40,7 @@
#include "smsdk_ext.h" #include "smsdk_ext.h"
#include <IBinTools.h> #include <IBinTools.h>
#include <ISDKTools.h> #include <ISDKTools.h>
#ifndef WIN32
#include "CDetour/detours.h" #include "CDetour/detours.h"
#endif
#include "ihltvdirector.h" #include "ihltvdirector.h"
#include "ihltv.h" #include "ihltv.h"
#include "iserver.h" #include "iserver.h"

View File

@ -32,6 +32,7 @@
#include "extension.h" #include "extension.h"
#include "forwards.h" #include "forwards.h"
#include "hltvserverwrapper.h" #include "hltvserverwrapper.h"
#include "commonhooks.h"
CForwardManager g_pSTVForwards; CForwardManager g_pSTVForwards;
@ -128,6 +129,8 @@ void CForwardManager::Init()
m_SpectatorDisconnectFwd = forwards->CreateForward("SourceTV_OnSpectatorDisconnect", ET_Ignore, 2, NULL, Param_Cell, Param_String); m_SpectatorDisconnectFwd = forwards->CreateForward("SourceTV_OnSpectatorDisconnect", ET_Ignore, 2, NULL, Param_Cell, Param_String);
m_SpectatorDisconnectedFwd = forwards->CreateForward("SourceTV_OnSpectatorDisconnected", ET_Ignore, 2, NULL, Param_Cell, Param_String); m_SpectatorDisconnectedFwd = forwards->CreateForward("SourceTV_OnSpectatorDisconnected", ET_Ignore, 2, NULL, Param_Cell, Param_String);
m_SpectatorPutInServerFwd = forwards->CreateForward("SourceTV_OnSpectatorPutInServer", ET_Ignore, 1, NULL, Param_Cell); m_SpectatorPutInServerFwd = forwards->CreateForward("SourceTV_OnSpectatorPutInServer", ET_Ignore, 1, NULL, Param_Cell);
m_SpectatorChatMessageFwd = forwards->CreateForward("SourceTV_OnSpectatorChatMessage", ET_Hook, 3, NULL, Param_Cell, Param_String, Param_String);
m_SpectatorChatMessagePostFwd = forwards->CreateForward("SourceTV_OnSpectatorChatMessage_Post", ET_Ignore, 3, NULL, Param_Cell, Param_String, Param_String);
m_ServerStartFwd = forwards->CreateForward("SourceTV_OnServerStart", ET_Ignore, 1, NULL, Param_Cell); m_ServerStartFwd = forwards->CreateForward("SourceTV_OnServerStart", ET_Ignore, 1, NULL, Param_Cell);
m_ServerShutdownFwd = forwards->CreateForward("SourceTV_OnServerShutdown", ET_Ignore, 1, NULL, Param_Cell); m_ServerShutdownFwd = forwards->CreateForward("SourceTV_OnServerShutdown", ET_Ignore, 1, NULL, Param_Cell);
@ -142,6 +145,8 @@ void CForwardManager::Shutdown()
forwards->ReleaseForward(m_SpectatorDisconnectFwd); forwards->ReleaseForward(m_SpectatorDisconnectFwd);
forwards->ReleaseForward(m_SpectatorDisconnectedFwd); forwards->ReleaseForward(m_SpectatorDisconnectedFwd);
forwards->ReleaseForward(m_SpectatorPutInServerFwd); forwards->ReleaseForward(m_SpectatorPutInServerFwd);
forwards->ReleaseForward(m_SpectatorChatMessageFwd);
forwards->ReleaseForward(m_SpectatorChatMessagePostFwd);
forwards->ReleaseForward(m_ServerStartFwd); forwards->ReleaseForward(m_ServerStartFwd);
forwards->ReleaseForward(m_ServerShutdownFwd); forwards->ReleaseForward(m_ServerShutdownFwd);
@ -206,6 +211,9 @@ void CForwardManager::UnhookServer(HLTVServerWrapper *wrapper)
void CForwardManager::HookClient(IClient *client) void CForwardManager::HookClient(IClient *client)
{ {
// Hook ExecuteStringCommand for chat messages
g_pSTVCommonHooks.AddSpectatorHook(this, client);
void *pGameClient = (void *)((intptr_t)client - 4); void *pGameClient = (void *)((intptr_t)client - 4);
if (m_bHasActivatePlayerOffset) if (m_bHasActivatePlayerOffset)
SH_ADD_MANUALHOOK(CBaseClient_ActivatePlayer, pGameClient, SH_MEMBER(this, &CForwardManager::OnSpectatorPutInServer), true); SH_ADD_MANUALHOOK(CBaseClient_ActivatePlayer, pGameClient, SH_MEMBER(this, &CForwardManager::OnSpectatorPutInServer), true);
@ -221,6 +229,9 @@ void CForwardManager::HookClient(IClient *client)
void CForwardManager::UnhookClient(IClient *client) void CForwardManager::UnhookClient(IClient *client)
{ {
// Remove ExecuteStringCommand hook
g_pSTVCommonHooks.RemoveSpectatorHook(this, client);
void *pGameClient = (void *)((intptr_t)client - 4); void *pGameClient = (void *)((intptr_t)client - 4);
if (m_bHasActivatePlayerOffset) if (m_bHasActivatePlayerOffset)
SH_REMOVE_MANUALHOOK(CBaseClient_ActivatePlayer, pGameClient, SH_MEMBER(this, &CForwardManager::OnSpectatorPutInServer), true); SH_REMOVE_MANUALHOOK(CBaseClient_ActivatePlayer, pGameClient, SH_MEMBER(this, &CForwardManager::OnSpectatorPutInServer), true);
@ -421,6 +432,119 @@ void CForwardManager::OnSpectatorPutInServer()
RETURN_META(MRES_IGNORED); RETURN_META(MRES_IGNORED);
} }
bool CForwardManager::OnSpectatorExecuteStringCommand(const char *s)
{
IClient *client = META_IFACEPTR(IClient);
if (!s || !s[0])
RETURN_META_VALUE(MRES_IGNORED, true);
CCommand args;
if (!args.Tokenize(s))
RETURN_META_VALUE(MRES_IGNORED, true);
// See if the client wants to chat.
if (!Q_stricmp(args[0], "say") && args.ArgC() > 1)
{
// TODO find correct hltvserver this client is connected to!
// Save the client index and message.
hltvserver->SetLastChatClient(client);
hltvserver->SetLastChatMessage(args[1]);
/*bool ret = SH_CALL(client, &IClient::ExecuteStringCommand)(s);
hltvserver->SetLastChatClient(0);
hltvserver->SetLastChatMessage(nullptr);
RETURN_META_VALUE(MRES_SUPERCEDE, ret);*/
}
RETURN_META_VALUE(MRES_IGNORED, true);
}
DETOUR_DECL_MEMBER2(DetourHLTVServer_BroadcastLocalChat, void, const char *, chat, const char *, chatgroup)
{
// IServer is +8 from CHLTVServer due to multiple inheritance
IServer *server = (IServer *)((intptr_t)this + 8);
HLTVServerWrapper *wrapper = g_HLTVServers.GetWrapper(server);
char chatBuffer[256], groupBuffer[256];
// TODO: Use saved wrapper->GetLastChatMessage() and add "name : " manually again after plugins are done.
ke::SafeStrcpy(chatBuffer, sizeof(chatBuffer), chat);
ke::SafeStrcpy(groupBuffer, sizeof(groupBuffer), chatgroup);
if (wrapper)
{
// Call the forward for this message.
bool supercede = g_pSTVForwards.CallOnSpectatorChatMessage(wrapper, chatBuffer, sizeof(chatBuffer), groupBuffer, sizeof(groupBuffer));
if (supercede)
return;
}
// Call the engine function with our modified parameters.
DETOUR_MEMBER_CALL(DetourHLTVServer_BroadcastLocalChat)(chatBuffer, groupBuffer);
if (wrapper)
{
g_pSTVForwards.CallOnSpectatorChatMessage_Post(wrapper, chatBuffer, groupBuffer);
}
}
void CForwardManager::CreateBroadcastLocalChatDetour()
{
if (m_bBroadcastLocalChatDetoured)
return;
m_DBroadcastLocalChat = DETOUR_CREATE_MEMBER(DetourHLTVServer_BroadcastLocalChat, "CHLTVServer::BroadcastLocalChat");
if (m_DBroadcastLocalChat != nullptr)
{
m_DBroadcastLocalChat->EnableDetour();
m_bBroadcastLocalChatDetoured = true;
return;
}
smutils->LogError(myself, "CHLTVServer::BroadcastLocalChat detour could not be initialized.");
}
void CForwardManager::RemoveBroadcastLocalChatDetour()
{
if (m_DBroadcastLocalChat != nullptr)
{
m_DBroadcastLocalChat->Destroy();
m_DBroadcastLocalChat = nullptr;
}
m_bBroadcastLocalChatDetoured = false;
}
bool CForwardManager::CallOnSpectatorChatMessage(HLTVServerWrapper *server, char *msg, int msglen, char *chatgroup, int grouplen)
{
int clientIndex = 0;
IClient *client = server->GetLastChatClient();
if (client)
clientIndex = client->GetPlayerSlot() + 1;
m_SpectatorChatMessageFwd->PushCell(clientIndex);
m_SpectatorChatMessageFwd->PushStringEx(msg, msglen, SM_PARAM_STRING_UTF8 | SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
m_SpectatorChatMessageFwd->PushStringEx(chatgroup, grouplen, SM_PARAM_STRING_UTF8 | SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
cell_t res = Pl_Continue;
m_SpectatorChatMessageFwd->Execute(&res);
if (res >= Pl_Handled)
return true;
return false;
}
void CForwardManager::CallOnSpectatorChatMessage_Post(HLTVServerWrapper *server, const char *msg, const char *chatgroup)
{
int clientIndex = 0;
IClient *client = server->GetLastChatClient();
if (client)
clientIndex = client->GetPlayerSlot() + 1;
m_SpectatorChatMessagePostFwd->PushCell(clientIndex);
m_SpectatorChatMessagePostFwd->PushString(msg);
m_SpectatorChatMessagePostFwd->PushString(chatgroup);
m_SpectatorChatMessagePostFwd->Execute();
}
// These two hooks are actually only hooked on windows. // These two hooks are actually only hooked on windows.
void CForwardManager::OnStartRecording_Post(const char *filename, bool bContinuously) void CForwardManager::OnStartRecording_Post(const char *filename, bool bContinuously)
@ -506,10 +630,10 @@ DETOUR_DECL_MEMBER0(DetourHLTVStopRecording, void)
#endif #endif
} }
bool CForwardManager::CreateStartRecordingDetour() void CForwardManager::CreateStartRecordingDetour()
{ {
if (m_bStartRecordingDetoured) if (m_bStartRecordingDetoured)
return true; return;
m_DStartRecording = DETOUR_CREATE_MEMBER(DetourHLTVStartRecording, "CHLTVDemoRecorder::StartRecording"); m_DStartRecording = DETOUR_CREATE_MEMBER(DetourHLTVStartRecording, "CHLTVDemoRecorder::StartRecording");
@ -517,10 +641,10 @@ bool CForwardManager::CreateStartRecordingDetour()
{ {
m_DStartRecording->EnableDetour(); m_DStartRecording->EnableDetour();
m_bStartRecordingDetoured = true; m_bStartRecordingDetoured = true;
return true; return;
} }
smutils->LogError(myself, "CHLTVDemoRecorder::StartRecording detour could not be initialized."); smutils->LogError(myself, "CHLTVDemoRecorder::StartRecording detour could not be initialized.");
return false; return;
} }
void CForwardManager::RemoveStartRecordingDetour() void CForwardManager::RemoveStartRecordingDetour()
@ -533,10 +657,10 @@ void CForwardManager::RemoveStartRecordingDetour()
m_bStartRecordingDetoured = false; m_bStartRecordingDetoured = false;
} }
bool CForwardManager::CreateStopRecordingDetour() void CForwardManager::CreateStopRecordingDetour()
{ {
if (m_bStopRecordingDetoured) if (m_bStopRecordingDetoured)
return true; return;
m_DStopRecording = DETOUR_CREATE_MEMBER(DetourHLTVStopRecording, "CHLTVDemoRecorder::StopRecording"); m_DStopRecording = DETOUR_CREATE_MEMBER(DetourHLTVStopRecording, "CHLTVDemoRecorder::StopRecording");
@ -544,10 +668,10 @@ bool CForwardManager::CreateStopRecordingDetour()
{ {
m_DStopRecording->EnableDetour(); m_DStopRecording->EnableDetour();
m_bStopRecordingDetoured = true; m_bStopRecordingDetoured = true;
return true; return;
} }
smutils->LogError(myself, "CHLTVDemoRecorder::StopRecording detour could not be initialized."); smutils->LogError(myself, "CHLTVDemoRecorder::StopRecording detour could not be initialized.");
return false; return;
} }
void CForwardManager::RemoveStopRecordingDetour() void CForwardManager::RemoveStopRecordingDetour()

View File

@ -70,9 +70,9 @@ public:
void UnhookServer(HLTVServerWrapper *server); void UnhookServer(HLTVServerWrapper *server);
#ifndef WIN32 #ifndef WIN32
bool CreateStartRecordingDetour(); void CreateStartRecordingDetour();
void RemoveStartRecordingDetour(); void RemoveStartRecordingDetour();
bool CreateStopRecordingDetour(); void CreateStopRecordingDetour();
void RemoveStopRecordingDetour(); void RemoveStopRecordingDetour();
#endif #endif
@ -82,6 +82,13 @@ public:
void CallOnStartRecording(IDemoRecorder *recorder, const char *filename, bool bContinuously); void CallOnStartRecording(IDemoRecorder *recorder, const char *filename, bool bContinuously);
void CallOnStopRecording(IDemoRecorder *recorder); void CallOnStopRecording(IDemoRecorder *recorder);
bool CallOnSpectatorChatMessage(HLTVServerWrapper *server, char *msg, int msglen, char *chatgroup, int grouplen);
void CallOnSpectatorChatMessage_Post(HLTVServerWrapper *server, const char *msg, const char *chatgroup);
bool OnSpectatorExecuteStringCommand(const char *s);
void CreateBroadcastLocalChatDetour();
void RemoveBroadcastLocalChatDetour();
private: private:
void HookClient(IClient *client); void HookClient(IClient *client);
void UnhookClient(IClient *client); void UnhookClient(IClient *client);
@ -112,6 +119,8 @@ private:
IForward *m_SpectatorDisconnectFwd; IForward *m_SpectatorDisconnectFwd;
IForward *m_SpectatorDisconnectedFwd; IForward *m_SpectatorDisconnectedFwd;
IForward *m_SpectatorPutInServerFwd; IForward *m_SpectatorPutInServerFwd;
IForward *m_SpectatorChatMessageFwd;
IForward *m_SpectatorChatMessagePostFwd;
IForward *m_ServerStartFwd; IForward *m_ServerStartFwd;
IForward *m_ServerShutdownFwd; IForward *m_ServerShutdownFwd;
@ -122,6 +131,9 @@ private:
bool m_bHasActivatePlayerOffset = false; bool m_bHasActivatePlayerOffset = false;
bool m_bHasDisconnectOffset = false; bool m_bHasDisconnectOffset = false;
bool m_bBroadcastLocalChatDetoured = false;
CDetour *m_DBroadcastLocalChat = nullptr;
// Only need the detours on linux. Windows always uses its vtables.. // Only need the detours on linux. Windows always uses its vtables..
#ifndef WIN32 #ifndef WIN32
bool m_bStartRecordingDetoured = false; bool m_bStartRecordingDetoured = false;

View File

@ -1,10 +1,10 @@
#include "hltvserverwrapper.h" #include "hltvserverwrapper.h"
#include "forwards.h" #include "forwards.h"
#include "commonhooks.h"
void *old_host_client = nullptr; void *old_host_client = nullptr;
bool g_HostClientOverridden = false; bool g_HostClientOverridden = false;
SH_DECL_HOOK1(IClient, ExecuteStringCommand, SH_NOATTRIB, 0, bool, const char *);
SH_DECL_MANUALHOOK0_void(CHLTVServer_Shutdown, 0, 0, 0); SH_DECL_MANUALHOOK0_void(CHLTVServer_Shutdown, 0, 0, 0);
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
@ -30,6 +30,7 @@ HLTVServerWrapper::HLTVServerWrapper(IHLTVServer *hltvserver)
m_HLTVServer = hltvserver; m_HLTVServer = hltvserver;
m_DemoRecorder = g_HLTVServers.GetDemoRecorderPtr(hltvserver); m_DemoRecorder = g_HLTVServers.GetDemoRecorderPtr(hltvserver);
m_Connected = true; m_Connected = true;
m_LastChatClient = nullptr;
Hook(); Hook();
@ -84,6 +85,26 @@ int HLTVServerWrapper::GetInstanceNumber()
return g_HLTVServers.GetInstanceNumber(m_HLTVServer); return g_HLTVServers.GetInstanceNumber(m_HLTVServer);
} }
IClient *HLTVServerWrapper::GetLastChatClient()
{
return m_LastChatClient;
}
void HLTVServerWrapper::SetLastChatClient(IClient *client)
{
m_LastChatClient = client;
}
const char *HLTVServerWrapper::GetLastChatMessage()
{
return m_LastChatMessage;
}
void HLTVServerWrapper::SetLastChatMessage(const char *msg)
{
m_LastChatMessage = msg;
}
HLTVClientWrapper *HLTVServerWrapper::GetClient(int index) HLTVClientWrapper *HLTVServerWrapper::GetClient(int index)
{ {
// Grow the vector with null pointers // Grow the vector with null pointers
@ -123,8 +144,8 @@ void HLTVServerWrapper::Hook()
IClient *pClient = iserver->GetClient(m_HLTVServer->GetHLTVSlot()); IClient *pClient = iserver->GetClient(m_HLTVServer->GetHLTVSlot());
if (pClient) if (pClient)
{ {
SH_ADD_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand), false); // Hook ExecuteStringCommand
SH_ADD_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true); g_pSTVCommonHooks.AddHLTVClientHook(this, pClient);
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
SH_ADD_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false); SH_ADD_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false);
#ifndef WIN32 #ifndef WIN32
@ -155,8 +176,8 @@ void HLTVServerWrapper::Unhook()
IClient *pClient = iserver->GetClient(m_HLTVServer->GetHLTVSlot()); IClient *pClient = iserver->GetClient(m_HLTVServer->GetHLTVSlot());
if (pClient) if (pClient)
{ {
SH_REMOVE_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand), false); // Remove ExecuteStringCommand hook
SH_REMOVE_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true); g_pSTVCommonHooks.RemoveHLTVClientHook(this, pClient);
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
SH_REMOVE_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false); SH_REMOVE_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false);
#ifndef WIN32 #ifndef WIN32
@ -327,6 +348,7 @@ void HLTVServerWrapperManager::InitHooks()
void HLTVServerWrapperManager::ShutdownHooks() void HLTVServerWrapperManager::ShutdownHooks()
{ {
g_pSTVForwards.RemoveBroadcastLocalChatDetour();
#ifndef WIN32 #ifndef WIN32
g_pSTVForwards.RemoveStartRecordingDetour(); g_pSTVForwards.RemoveStartRecordingDetour();
g_pSTVForwards.RemoveStopRecordingDetour(); g_pSTVForwards.RemoveStopRecordingDetour();
@ -343,8 +365,9 @@ void HLTVServerWrapperManager::ShutdownHooks()
void HLTVServerWrapperManager::AddServer(IHLTVServer *hltvserver) void HLTVServerWrapperManager::AddServer(IHLTVServer *hltvserver)
{ {
#ifndef WIN32
// Create the detours once the first sourcetv server is created. // Create the detours once the first sourcetv server is created.
g_pSTVForwards.CreateBroadcastLocalChatDetour();
#ifndef WIN32
g_pSTVForwards.CreateStartRecordingDetour(); g_pSTVForwards.CreateStartRecordingDetour();
g_pSTVForwards.CreateStopRecordingDetour(); g_pSTVForwards.CreateStopRecordingDetour();
#endif #endif

View File

@ -48,13 +48,19 @@ public:
HLTVClientWrapper *GetClient(int index); HLTVClientWrapper *GetClient(int index);
int GetInstanceNumber(); int GetInstanceNumber();
IClient *GetLastChatClient();
void SetLastChatClient(IClient *client);
const char *GetLastChatMessage();
void SetLastChatMessage(const char *msg);
bool OnHLTVBotExecuteStringCommand(const char *s);
bool OnHLTVBotExecuteStringCommand_Post(const char *s);
private: private:
void Hook(); void Hook();
void Unhook(); void Unhook();
// Hooks // Hooks
bool OnHLTVBotExecuteStringCommand(const char *s);
bool OnHLTVBotExecuteStringCommand_Post(const char *s);
void OnHLTVServerShutdown(); void OnHLTVServerShutdown();
#if SOURCE_ENGINE != SE_CSGO #if SOURCE_ENGINE != SE_CSGO
@ -68,6 +74,9 @@ private:
IHLTVServer *m_HLTVServer = nullptr; IHLTVServer *m_HLTVServer = nullptr;
IDemoRecorder *m_DemoRecorder = nullptr; IDemoRecorder *m_DemoRecorder = nullptr;
ke::Vector<ke::AutoPtr<HLTVClientWrapper>> m_Clients; ke::Vector<ke::AutoPtr<HLTVClientWrapper>> m_Clients;
IClient *m_LastChatClient = nullptr;
const char *m_LastChatMessage = nullptr;
}; };
class HLTVServerWrapperManager class HLTVServerWrapperManager

View File

@ -87,6 +87,17 @@ public SourceTV_OnSpectatorDisconnected(client, const String:reason[255])
PrintToServer("SourceTV client %d disconnected (isconnected %d) with reason -> %s.", client, SourceTV_IsClientConnected(client), reason); PrintToServer("SourceTV client %d disconnected (isconnected %d) with reason -> %s.", client, SourceTV_IsClientConnected(client), reason);
} }
public Action:SourceTV_OnSpectatorChatMessage(client, String:message[255], String:chatgroup[255])
{
PrintToServer("SourceTV client %d (chatgroup \"%s\") writes: %s", client, chatgroup, message);
return Plugin_Continue;
}
public SourceTV_OnSpectatorChatMessage_Post(client, const String:message[], const String:chatgroup[])
{
PrintToServer("SourceTV client %d (chatgroup \"%s\") wrote: %s", client, chatgroup, message);
}
public Action:Cmd_GetServerCount(client, args) public Action:Cmd_GetServerCount(client, args)
{ {
ReplyToCommand(client, "SourceTV server count: %d", SourceTV_GetServerInstanceCount()); ReplyToCommand(client, "SourceTV server count: %d", SourceTV_GetServerInstanceCount());

View File

@ -115,6 +115,14 @@
"windows" "\x55\x8B\xEC\x83\xEC\x4C\x53\x8B\xD9\xC7\x45\xB4\x2A\x2A\x2A\x2A\x56\x8D" "windows" "\x55\x8B\xEC\x83\xEC\x4C\x53\x8B\xD9\xC7\x45\xB4\x2A\x2A\x2A\x2A\x56\x8D"
} }
"CHLTVServer::BroadcastLocalChat"
{
"library" "engine"
"linux" "@_ZN11CHLTVServer18BroadcastLocalChatEPKcS1_"
// "hltv_chat"
"windows" "\x55\x8B\xEC\x83\xEC\x54\xA1\x2A\x2A\x2A\x2A\x53"
}
"CHLTVServer::GetRecordingDemoFilename" "CHLTVServer::GetRecordingDemoFilename"
{ {
"library" "engine" "library" "engine"
@ -274,6 +282,14 @@
"windows" "\x55\x8B\xEC\x81\xEC\x44\x04\x00\x00\x53" "windows" "\x55\x8B\xEC\x81\xEC\x44\x04\x00\x00\x53"
} }
"CHLTVServer::BroadcastLocalChat"
{
"library" "engine"
"linux" "@_ZN11CHLTVServer18BroadcastLocalChatEPKcS1_"
// "hltv_chat"
"windows" "\x55\x8B\xEC\x81\xEC\x4C\x04\x00\x00\x53\x8B\xD9"
}
"CHLTVServer::Shutdown" "CHLTVServer::Shutdown"
{ {
"library" "engine" "library" "engine"

View File

@ -434,6 +434,29 @@ forward SourceTV_OnSpectatorDisconnected(client, const String:reason[255]);
*/ */
forward SourceTV_OnSpectatorPutInServer(client); forward SourceTV_OnSpectatorPutInServer(client);
/**
* Called before a spectator's chat message is sent.
* The message and chat group can be changed.
* Only called for directly connected clients - no proxies.
*
* @param client The spectator client index.
* @param message The message the client typed.
* @param chatgroup The chatgroup this message is sent to (tv_chatgroup).
* @return >= Plugin_Handled to block the message, Plugin_Continue to let it through.
*/
forward Action:SourceTV_OnSpectatorChatMessage(client, String:message[255], String:chatgroup[255]);
/**
* Called after a spectator wrote a chat message.
* Only called for directly connected clients - no proxies.
*
* @param client The spectator client index.
* @param message The message the client typed.
* @param chatgroup The chatgroup this message is sent to (tv_chatgroup).
* @noreturn
*/
forward SourceTV_OnSpectatorChatMessage_Post(client, const String:message[], const String:chatgroup[]);
/** /**
* Do not edit below this line! * Do not edit below this line!
*/ */