diff --git a/AMBuilder b/AMBuilder index 9e5725d..37120f6 100644 --- a/AMBuilder +++ b/AMBuilder @@ -6,11 +6,14 @@ projectName = 'sourcetvmanager' # smsdk_ext.cpp will be automatically added later sourceFiles = [ 'extension.cpp', + 'commonhooks.cpp', 'natives.cpp', 'forwards.cpp', 'hltvserverwrapper.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) 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': compiler.cxxincludes += [ os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'), diff --git a/commonhooks.cpp b/commonhooks.cpp new file mode 100644 index 0000000..b4c68f0 --- /dev/null +++ b/commonhooks.cpp @@ -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 . +* +* 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$ +*/ + +#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); +} \ No newline at end of file diff --git a/commonhooks.h b/commonhooks.h new file mode 100644 index 0000000..1a65527 --- /dev/null +++ b/commonhooks.h @@ -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 . +* +* 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_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_ diff --git a/extension.cpp b/extension.cpp index 94a8ffc..a13dc87 100644 --- a/extension.cpp +++ b/extension.cpp @@ -95,9 +95,7 @@ bool SourceTVManager::SDK_OnLoad(char *error, size_t maxlength, bool late) g_HLTVServers.InitHooks(); -#ifndef WIN32 CDetourManager::Init(smutils->GetScriptingEngine(), g_pGameConf); -#endif sharesys->AddNatives(myself, sourcetv_natives); sharesys->RegisterLibrary(myself, "sourcetvmanager"); diff --git a/extension.h b/extension.h index e0cbd25..e3b199c 100644 --- a/extension.h +++ b/extension.h @@ -40,9 +40,7 @@ #include "smsdk_ext.h" #include #include -#ifndef WIN32 #include "CDetour/detours.h" -#endif #include "ihltvdirector.h" #include "ihltv.h" #include "iserver.h" diff --git a/forwards.cpp b/forwards.cpp index 9011852..430b907 100644 --- a/forwards.cpp +++ b/forwards.cpp @@ -32,6 +32,7 @@ #include "extension.h" #include "forwards.h" #include "hltvserverwrapper.h" +#include "commonhooks.h" 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_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_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_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_SpectatorDisconnectedFwd); forwards->ReleaseForward(m_SpectatorPutInServerFwd); + forwards->ReleaseForward(m_SpectatorChatMessageFwd); + forwards->ReleaseForward(m_SpectatorChatMessagePostFwd); forwards->ReleaseForward(m_ServerStartFwd); forwards->ReleaseForward(m_ServerShutdownFwd); @@ -206,6 +211,9 @@ void CForwardManager::UnhookServer(HLTVServerWrapper *wrapper) void CForwardManager::HookClient(IClient *client) { + // Hook ExecuteStringCommand for chat messages + g_pSTVCommonHooks.AddSpectatorHook(this, client); + void *pGameClient = (void *)((intptr_t)client - 4); if (m_bHasActivatePlayerOffset) 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) { + // Remove ExecuteStringCommand hook + g_pSTVCommonHooks.RemoveSpectatorHook(this, client); + void *pGameClient = (void *)((intptr_t)client - 4); if (m_bHasActivatePlayerOffset) SH_REMOVE_MANUALHOOK(CBaseClient_ActivatePlayer, pGameClient, SH_MEMBER(this, &CForwardManager::OnSpectatorPutInServer), true); @@ -421,6 +432,119 @@ void CForwardManager::OnSpectatorPutInServer() 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. void CForwardManager::OnStartRecording_Post(const char *filename, bool bContinuously) @@ -506,10 +630,10 @@ DETOUR_DECL_MEMBER0(DetourHLTVStopRecording, void) #endif } -bool CForwardManager::CreateStartRecordingDetour() +void CForwardManager::CreateStartRecordingDetour() { if (m_bStartRecordingDetoured) - return true; + return; m_DStartRecording = DETOUR_CREATE_MEMBER(DetourHLTVStartRecording, "CHLTVDemoRecorder::StartRecording"); @@ -517,10 +641,10 @@ bool CForwardManager::CreateStartRecordingDetour() { m_DStartRecording->EnableDetour(); m_bStartRecordingDetoured = true; - return true; + return; } smutils->LogError(myself, "CHLTVDemoRecorder::StartRecording detour could not be initialized."); - return false; + return; } void CForwardManager::RemoveStartRecordingDetour() @@ -533,10 +657,10 @@ void CForwardManager::RemoveStartRecordingDetour() m_bStartRecordingDetoured = false; } -bool CForwardManager::CreateStopRecordingDetour() +void CForwardManager::CreateStopRecordingDetour() { if (m_bStopRecordingDetoured) - return true; + return; m_DStopRecording = DETOUR_CREATE_MEMBER(DetourHLTVStopRecording, "CHLTVDemoRecorder::StopRecording"); @@ -544,10 +668,10 @@ bool CForwardManager::CreateStopRecordingDetour() { m_DStopRecording->EnableDetour(); m_bStopRecordingDetoured = true; - return true; + return; } smutils->LogError(myself, "CHLTVDemoRecorder::StopRecording detour could not be initialized."); - return false; + return; } void CForwardManager::RemoveStopRecordingDetour() diff --git a/forwards.h b/forwards.h index 5e11c4e..4271f9b 100644 --- a/forwards.h +++ b/forwards.h @@ -70,9 +70,9 @@ public: void UnhookServer(HLTVServerWrapper *server); #ifndef WIN32 - bool CreateStartRecordingDetour(); + void CreateStartRecordingDetour(); void RemoveStartRecordingDetour(); - bool CreateStopRecordingDetour(); + void CreateStopRecordingDetour(); void RemoveStopRecordingDetour(); #endif @@ -82,6 +82,13 @@ public: void CallOnStartRecording(IDemoRecorder *recorder, const char *filename, bool bContinuously); 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: void HookClient(IClient *client); void UnhookClient(IClient *client); @@ -112,6 +119,8 @@ private: IForward *m_SpectatorDisconnectFwd; IForward *m_SpectatorDisconnectedFwd; IForward *m_SpectatorPutInServerFwd; + IForward *m_SpectatorChatMessageFwd; + IForward *m_SpectatorChatMessagePostFwd; IForward *m_ServerStartFwd; IForward *m_ServerShutdownFwd; @@ -122,6 +131,9 @@ private: bool m_bHasActivatePlayerOffset = false; bool m_bHasDisconnectOffset = false; + bool m_bBroadcastLocalChatDetoured = false; + CDetour *m_DBroadcastLocalChat = nullptr; + // Only need the detours on linux. Windows always uses its vtables.. #ifndef WIN32 bool m_bStartRecordingDetoured = false; diff --git a/hltvserverwrapper.cpp b/hltvserverwrapper.cpp index 462dd2d..5f0b792 100644 --- a/hltvserverwrapper.cpp +++ b/hltvserverwrapper.cpp @@ -1,10 +1,10 @@ #include "hltvserverwrapper.h" #include "forwards.h" +#include "commonhooks.h" void *old_host_client = nullptr; bool g_HostClientOverridden = false; -SH_DECL_HOOK1(IClient, ExecuteStringCommand, SH_NOATTRIB, 0, bool, const char *); SH_DECL_MANUALHOOK0_void(CHLTVServer_Shutdown, 0, 0, 0); #if SOURCE_ENGINE != SE_CSGO @@ -30,6 +30,7 @@ HLTVServerWrapper::HLTVServerWrapper(IHLTVServer *hltvserver) m_HLTVServer = hltvserver; m_DemoRecorder = g_HLTVServers.GetDemoRecorderPtr(hltvserver); m_Connected = true; + m_LastChatClient = nullptr; Hook(); @@ -84,6 +85,26 @@ int HLTVServerWrapper::GetInstanceNumber() 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) { // Grow the vector with null pointers @@ -123,8 +144,8 @@ void HLTVServerWrapper::Hook() IClient *pClient = iserver->GetClient(m_HLTVServer->GetHLTVSlot()); if (pClient) { - SH_ADD_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand), false); - SH_ADD_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true); + // Hook ExecuteStringCommand + g_pSTVCommonHooks.AddHLTVClientHook(this, pClient); #if SOURCE_ENGINE != SE_CSGO SH_ADD_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false); #ifndef WIN32 @@ -155,8 +176,8 @@ void HLTVServerWrapper::Unhook() IClient *pClient = iserver->GetClient(m_HLTVServer->GetHLTVSlot()); if (pClient) { - SH_REMOVE_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand), false); - SH_REMOVE_HOOK(IClient, ExecuteStringCommand, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnHLTVBotExecuteStringCommand_Post), true); + // Remove ExecuteStringCommand hook + g_pSTVCommonHooks.RemoveHLTVClientHook(this, pClient); #if SOURCE_ENGINE != SE_CSGO SH_REMOVE_HOOK(IClient, ClientPrintf, pClient, SH_MEMBER(this, &HLTVServerWrapper::OnIClient_ClientPrintf_Post), false); #ifndef WIN32 @@ -327,6 +348,7 @@ void HLTVServerWrapperManager::InitHooks() void HLTVServerWrapperManager::ShutdownHooks() { + g_pSTVForwards.RemoveBroadcastLocalChatDetour(); #ifndef WIN32 g_pSTVForwards.RemoveStartRecordingDetour(); g_pSTVForwards.RemoveStopRecordingDetour(); @@ -343,8 +365,9 @@ void HLTVServerWrapperManager::ShutdownHooks() void HLTVServerWrapperManager::AddServer(IHLTVServer *hltvserver) { -#ifndef WIN32 // Create the detours once the first sourcetv server is created. + g_pSTVForwards.CreateBroadcastLocalChatDetour(); +#ifndef WIN32 g_pSTVForwards.CreateStartRecordingDetour(); g_pSTVForwards.CreateStopRecordingDetour(); #endif diff --git a/hltvserverwrapper.h b/hltvserverwrapper.h index 5482fa0..a211fa7 100644 --- a/hltvserverwrapper.h +++ b/hltvserverwrapper.h @@ -48,13 +48,19 @@ public: HLTVClientWrapper *GetClient(int index); 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: void Hook(); void Unhook(); // Hooks - bool OnHLTVBotExecuteStringCommand(const char *s); - bool OnHLTVBotExecuteStringCommand_Post(const char *s); void OnHLTVServerShutdown(); #if SOURCE_ENGINE != SE_CSGO @@ -68,6 +74,9 @@ private: IHLTVServer *m_HLTVServer = nullptr; IDemoRecorder *m_DemoRecorder = nullptr; ke::Vector> m_Clients; + + IClient *m_LastChatClient = nullptr; + const char *m_LastChatMessage = nullptr; }; class HLTVServerWrapperManager diff --git a/sourcetv_test.sp b/sourcetv_test.sp index aaa625c..4abc1c6 100644 --- a/sourcetv_test.sp +++ b/sourcetv_test.sp @@ -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); } +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) { ReplyToCommand(client, "SourceTV server count: %d", SourceTV_GetServerInstanceCount()); diff --git a/sourcetvmanager.games.txt b/sourcetvmanager.games.txt index f1483fc..cdc8987 100644 --- a/sourcetvmanager.games.txt +++ b/sourcetvmanager.games.txt @@ -115,6 +115,14 @@ "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" { "library" "engine" @@ -274,6 +282,14 @@ "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" { "library" "engine" diff --git a/sourcetvmanager.inc b/sourcetvmanager.inc index 86a1995..97bff67 100644 --- a/sourcetvmanager.inc +++ b/sourcetvmanager.inc @@ -434,6 +434,29 @@ forward SourceTV_OnSpectatorDisconnected(client, const String:reason[255]); */ 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! */