From d03b22abf6a8fa6d571ff633b641d3c7bd1e2e9c Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Thu, 3 Mar 2016 04:13:21 +0100 Subject: [PATCH] Add SourceTV_BroadcastChatMessage native Add option to send messages to locally connected spectators only or to replay proxies as well. --- natives.cpp | 90 +++++++++++++++++++++++++++++++++++++-- sourcetv_test.sp | 38 ++++++++++++++++- sourcetvmanager.games.txt | 16 +++++++ sourcetvmanager.inc | 16 ++++++- 4 files changed, 153 insertions(+), 7 deletions(-) diff --git a/natives.cpp b/natives.cpp index 13658b0..06c96eb 100644 --- a/natives.cpp +++ b/natives.cpp @@ -158,7 +158,48 @@ static cell_t Native_GetDelay(IPluginContext *pContext, const cell_t *params) return sp_ftoc(hltvdirector->GetDelay()); } -// native bool:SourceTV_BroadcastScreenMessage(const String:format[], any:...); +static bool BroadcastEventLocal(IHLTVServer *server, IGameEvent *event, bool bReliable) +{ + static ICallWrapper *pBroadcastEventLocal = nullptr; + + if (!pBroadcastEventLocal) + { + void *addr = nullptr; + if (!g_pGameConf->GetMemSig("CHLTVServer::BroadcastEventLocal", &addr) || !addr) + { + smutils->LogError(myself, "Failed to get CHLTVServer::BroadcastEventLocal signature."); + return false; + } + + PassInfo pass[2]; + pass[0].flags = PASSFLAG_BYVAL; + pass[0].type = PassType_Basic; + pass[0].size = sizeof(IGameEvent *); + pass[1].flags = PASSFLAG_BYVAL; + pass[1].type = PassType_Basic; + pass[1].size = sizeof(bool); + + pBroadcastEventLocal = bintools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2); + } + + if (pBroadcastEventLocal) + { + unsigned char vstk[sizeof(void *) + sizeof(IGameEvent *) + sizeof(bool)]; + unsigned char *vptr = vstk; + + *(void **)vptr = (void *)server; + vptr += sizeof(void *); + *(IGameEvent **)vptr = event; + vptr += sizeof(char *); + *(bool *)vptr = bReliable; + + pBroadcastEventLocal->Execute(vstk, NULL); + return true; + } + return false; +} + +// native bool:SourceTV_BroadcastScreenMessage(bool:bLocalOnly, const String:format[], any:...); static cell_t Native_BroadcastScreenMessage(IPluginContext *pContext, const cell_t *params) { if (hltvserver == nullptr) @@ -168,7 +209,7 @@ static cell_t Native_BroadcastScreenMessage(IPluginContext *pContext, const cell size_t len; { DetectExceptions eh(pContext); - len = smutils->FormatString(buffer, sizeof(buffer), pContext, params, 1); + len = smutils->FormatString(buffer, sizeof(buffer), pContext, params, 2); if (eh.HasException()) return 0; } @@ -178,10 +219,17 @@ static cell_t Native_BroadcastScreenMessage(IPluginContext *pContext, const cell return 0; msg->SetString("text", buffer); - hltvserver->BroadcastEvent(msg); + + int ret = 1; + bool bLocalOnly = params[1] != 0; + if (bLocalOnly) + hltvserver->BroadcastEvent(msg); + else + ret = BroadcastEventLocal(hltvserver, msg, false); + gameevents->FreeEvent(msg); - return 1; + return ret; } // native bool:SourceTV_BroadcastConsoleMessage(const String:format[], any:...); @@ -250,6 +298,39 @@ static cell_t Native_BroadcastConsoleMessage(IPluginContext *pContext, const cel return 1; } +// native bool:SourceTV_BroadcastChatMessage(bool:bLocalOnly, const String:format[], any:...); +static cell_t Native_BroadcastChatMessage(IPluginContext *pContext, const cell_t *params) +{ + if (hltvserver == nullptr) + return 0; + + char buffer[1024]; + size_t len; + { + DetectExceptions eh(pContext); + len = smutils->FormatString(buffer, sizeof(buffer), pContext, params, 2); + if (eh.HasException()) + return 0; + } + + IGameEvent *msg = gameevents->CreateEvent("hltv_chat", true); + if (!msg) + return 0; + + msg->SetString("text", buffer); + + int ret = 1; + bool bLocalOnly = params[1] != 0; + if (bLocalOnly) + hltvserver->BroadcastEvent(msg); + else + ret = BroadcastEventLocal(hltvserver, msg, false); + + gameevents->FreeEvent(msg); + + return ret; +} + // native SourceTV_GetViewEntity(); static cell_t Native_GetViewEntity(IPluginContext *pContext, const cell_t *params) { @@ -659,6 +740,7 @@ const sp_nativeinfo_t sourcetv_natives[] = { "SourceTV_GetDelay", Native_GetDelay }, { "SourceTV_BroadcastScreenMessage", Native_BroadcastScreenMessage }, { "SourceTV_BroadcastConsoleMessage", Native_BroadcastConsoleMessage }, + { "SourceTV_BroadcastChatMessage", Native_BroadcastChatMessage }, { "SourceTV_GetViewEntity", Native_GetViewEntity }, { "SourceTV_GetViewOrigin", Native_GetViewOrigin }, { "SourceTV_ForceFixedCameraShot", Native_ForceFixedCameraShot }, diff --git a/sourcetv_test.sp b/sourcetv_test.sp index d736b8c..ca5c311 100644 --- a/sourcetv_test.sp +++ b/sourcetv_test.sp @@ -15,6 +15,8 @@ public OnPluginStart() RegConsoleCmd("sm_getdelay", Cmd_GetDelay); RegConsoleCmd("sm_spectators", Cmd_Spectators); RegConsoleCmd("sm_spechintmsg", Cmd_SendHintMessage); + RegConsoleCmd("sm_specchat", Cmd_SendChatMessage); + RegConsoleCmd("sm_specchatlocal", Cmd_SendChatMessageLocal); RegConsoleCmd("sm_specmsg", Cmd_SendMessage); RegConsoleCmd("sm_viewentity", Cmd_GetViewEntity); RegConsoleCmd("sm_vieworigin", Cmd_GetViewOrigin); @@ -166,7 +168,7 @@ public Action:Cmd_SendHintMessage(client, args) GetCmdArgString(sMsg, sizeof(sMsg)); StripQuotes(sMsg); - new bool:bSent = SourceTV_BroadcastScreenMessage("%s", sMsg); + new bool:bSent = SourceTV_BroadcastScreenMessage(false, "%s", sMsg); ReplyToCommand(client, "SourceTV sending hint message (success %d): %s", bSent, sMsg); return Plugin_Handled; } @@ -188,6 +190,40 @@ public Action:Cmd_SendMessage(client, args) return Plugin_Handled; } +public Action:Cmd_SendChatMessage(client, args) +{ + if (args < 1) + { + ReplyToCommand(client, "Usage: sm_specchat "); + return Plugin_Handled; + } + + new String:sMsg[128]; + GetCmdArgString(sMsg, sizeof(sMsg)); + StripQuotes(sMsg); + + new bool:bSent = SourceTV_BroadcastChatMessage(false, "%s", sMsg); + ReplyToCommand(client, "SourceTV sending chat message to all spectators (including relays) (success %d): %s", bSent, sMsg); + return Plugin_Handled; +} + +public Action:Cmd_SendChatMessageLocal(client, args) +{ + if (args < 1) + { + ReplyToCommand(client, "Usage: sm_specchatlocal "); + return Plugin_Handled; + } + + new String:sMsg[128]; + GetCmdArgString(sMsg, sizeof(sMsg)); + StripQuotes(sMsg); + + new bool:bSent = SourceTV_BroadcastChatMessage(true, "%s", sMsg); + ReplyToCommand(client, "SourceTV sending chat message to local spectators (success %d): %s", bSent, sMsg); + return Plugin_Handled; +} + public Action:Cmd_GetViewEntity(client, args) { ReplyToCommand(client, "SourceTV view entity: %d", SourceTV_GetViewEntity()); diff --git a/sourcetvmanager.games.txt b/sourcetvmanager.games.txt index 66d4cf4..9e58ae8 100644 --- a/sourcetvmanager.games.txt +++ b/sourcetvmanager.games.txt @@ -70,6 +70,14 @@ // ping(CCommand const&) "Client ping times:\n" "windows" "\x55\x8B\xEC\x83\xE4\xC0\x83\xEC\x34\x83\x3D\x2A\x2A\x2A\x2A\x01\x53\x56\x57\x75\x2A" } + + "CHLTVServer::BroadcastEventLocal" + { + "library" "engine" + "linux" "@_ZN11CHLTVServer19BroadcastEventLocalEP10IGameEventb" + // "SourceTV broadcast local event: %s\n" + "windows" "\x55\x8B\xEC\x83\xEC\x4C\x53\x8B\xD9\xC7\x45\xB4\x2A\x2A\x2A\x2A\x56\x8D" + } } } "cstrike" @@ -154,6 +162,14 @@ // ping(CCommand const&) "Client ping times:\n" "windows" "\x55\x8B\xEC\x51\x83\x3D\x2A\x2A\x2A\x2A\x01\x75\x2A" } + + "CHLTVServer::BroadcastEventLocal" + { + "library" "engine" + "linux" "@_ZN11CHLTVServer19BroadcastEventLocalEP10IGameEventb" + // "SourceTV broadcast local event: %s\n" + "windows" "\x55\x8B\xEC\x81\xEC\x44\x04\x00\x00\x53" + } } } } \ No newline at end of file diff --git a/sourcetvmanager.inc b/sourcetvmanager.inc index dcf8451..46754c6 100644 --- a/sourcetvmanager.inc +++ b/sourcetvmanager.inc @@ -92,11 +92,12 @@ native Float:SourceTV_GetDelay(); * Print a center message to all SourceTV spectators for ~2 seconds. * Like the tv_msg command. * + * @param bLocalOnly Send only to directly connected spectators or proxies as well? * @param format The format string. * @param ... Variable number of format string arguments. * @return True if message was sent, false otherwise. */ -native bool:SourceTV_BroadcastScreenMessage(const String:format[], any:...); +native bool:SourceTV_BroadcastScreenMessage(bool:bLocalOnly, const String:format[], any:...); /** * Prints text to the console of all connected SourceTV spectators. @@ -107,7 +108,15 @@ native bool:SourceTV_BroadcastScreenMessage(const String:format[], any:...); */ native bool:SourceTV_BroadcastConsoleMessage(const String:format[], any:...); - +/** + * Print a chat message to all SourceTV spectators. + * + * @param bLocalOnly Send only to directly connected spectators or proxies as well? + * @param format The format string. + * @param ... Variable number of format string arguments. + * @return True if message was sent, false otherwise. + */ +native bool:SourceTV_BroadcastChatMessage(bool:bLocalOnly, const String:format[], any:...); /******************************************************************************** @@ -393,6 +402,7 @@ public __ext_stvmngr_SetNTVOptional() MarkNativeAsOptional("SourceTV_GetDelay"); MarkNativeAsOptional("SourceTV_BroadcastScreenMessage"); MarkNativeAsOptional("SourceTV_BroadcastConsoleMessage"); + MarkNativeAsOptional("SourceTV_BroadcastChatMessage"); MarkNativeAsOptional("SourceTV_GetViewEntity"); MarkNativeAsOptional("SourceTV_GetViewOrigin"); MarkNativeAsOptional("SourceTV_ForceFixedCameraShot"); @@ -408,6 +418,8 @@ public __ext_stvmngr_SetNTVOptional() MarkNativeAsOptional("SourceTV_GetClientCount"); MarkNativeAsOptional("SourceTV_IsClientConnected"); MarkNativeAsOptional("SourceTV_GetSpectatorName"); + MarkNativeAsOptional("SourceTV_GetSpectatorIP"); + MarkNativeAsOptional("SourceTV_GetSpectatorPassword"); MarkNativeAsOptional("SourceTV_KickClient"); } #endif