Add SourceTV_PrintToChat native

Send chat message to one client only
This commit is contained in:
Peace-Maker 2016-11-14 03:01:44 -06:00
parent 31dd491033
commit ef76571d74
4 changed files with 114 additions and 1 deletions

View File

@ -38,11 +38,14 @@
extern const sp_nativeinfo_t sourcetv_natives[]; extern const sp_nativeinfo_t sourcetv_natives[];
// Print to client consoles
SH_DECL_MANUALHOOK0_void_vafmt(CBaseServer_BroadcastPrintf, 0, 0, 0); SH_DECL_MANUALHOOK0_void_vafmt(CBaseServer_BroadcastPrintf, 0, 0, 0);
bool g_bHasClientPrintfOffset = false; bool g_bHasClientPrintfOffset = false;
SH_DECL_MANUALHOOK1_void(CBaseClient_FireGameEvent, 0, 0, 0, IGameEvent *);
void SetupNativeCalls() void SetupNativeCalls()
bool g_bHasClientFireGameEventOffset = false;
{ {
int offset = -1; int offset = -1;
if (!g_pGameConf->GetOffset("CBaseServer::BroadcastPrintf", &offset) || offset == -1) if (!g_pGameConf->GetOffset("CBaseServer::BroadcastPrintf", &offset) || offset == -1)
@ -54,6 +57,17 @@ void SetupNativeCalls()
SH_MANUALHOOK_RECONFIGURE(CBaseServer_BroadcastPrintf, offset, 0, 0); SH_MANUALHOOK_RECONFIGURE(CBaseServer_BroadcastPrintf, offset, 0, 0);
g_bHasClientPrintfOffset = true; g_bHasClientPrintfOffset = true;
} }
offset = -1;
if (!g_pGameConf->GetOffset("CBaseClient::FireGameEvent", &offset) || offset == -1)
{
smutils->LogError(myself, "Failed to get CBaseClient::FireGameEvent offset.");
}
else
{
SH_MANUALHOOK_RECONFIGURE(CBaseClient_FireGameEvent, offset, 0, 0);
g_bHasClientFireGameEventOffset = true;
}
} }
// native SourceTV_GetServerInstanceCount(); // native SourceTV_GetServerInstanceCount();
@ -786,6 +800,60 @@ static cell_t Native_KickClient(IPluginContext *pContext, const cell_t *params)
return 0; return 0;
} }
// native SourceTV_PrintToChat(client, const String:format[], any:...);
static cell_t Native_PrintToChat(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 = hltvserver->GetClient(client);
if (!pClient->IsConnected())
{
pContext->ReportError("Client %d is not connected.", client);
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;
#if SOURCE_ENGINE == SE_CSGO
wchar_t wBuffer[1024];
V_UTF8ToUnicode(buffer, wBuffer, sizeof(wBuffer));
msg->SetWString("text", wBuffer);
#else
msg->SetString("text", buffer);
#endif
if (g_bHasClientFireGameEventOffset)
{
void *pGameClient = pClient->BaseClient();
// The IClient vtable is +4 from the CBaseClient vtable due to multiple inheritance.
pGameClient = (void *)((intptr_t)pGameClient - 4);
SH_MCALL(pGameClient, CBaseClient_FireGameEvent)(msg);
}
gameevents->FreeEvent(msg);
return 0;
}
const sp_nativeinfo_t sourcetv_natives[] = const sp_nativeinfo_t sourcetv_natives[] =
{ {
{ "SourceTV_GetServerInstanceCount", Native_GetServerInstanceCount }, { "SourceTV_GetServerInstanceCount", Native_GetServerInstanceCount },
@ -822,5 +890,6 @@ const sp_nativeinfo_t sourcetv_natives[] =
{ "SourceTV_GetClientIP", Native_GetClientIP }, { "SourceTV_GetClientIP", Native_GetClientIP },
{ "SourceTV_GetClientPassword", Native_GetClientPassword }, { "SourceTV_GetClientPassword", Native_GetClientPassword },
{ "SourceTV_KickClient", Native_KickClient }, { "SourceTV_KickClient", Native_KickClient },
{ "SourceTV_PrintToChat", Native_PrintToChat },
{ NULL, NULL }, { NULL, NULL },
}; };

View File

@ -34,6 +34,7 @@ public OnPluginStart()
RegConsoleCmd("sm_democonsole", Cmd_PrintDemoConsole); RegConsoleCmd("sm_democonsole", Cmd_PrintDemoConsole);
RegConsoleCmd("sm_botcmd", Cmd_ExecuteStringCommand); RegConsoleCmd("sm_botcmd", Cmd_ExecuteStringCommand);
RegConsoleCmd("sm_speckick", Cmd_KickClient); RegConsoleCmd("sm_speckick", Cmd_KickClient);
RegConsoleCmd("sm_specchatone", Cmd_PrintToChat);
} }
public SourceTV_OnStartRecording(instance, const String:filename[]) public SourceTV_OnStartRecording(instance, const String:filename[])
@ -413,7 +414,7 @@ public Action:Cmd_ExecuteStringCommand(client, args)
public Action:Cmd_KickClient(client, args) public Action:Cmd_KickClient(client, args)
{ {
if (args < 1) if (args < 2)
{ {
ReplyToCommand(client, "Usage: sm_speckick <index> <reason>"); ReplyToCommand(client, "Usage: sm_speckick <index> <reason>");
return Plugin_Handled; return Plugin_Handled;
@ -429,4 +430,24 @@ public Action:Cmd_KickClient(client, args)
SourceTV_KickClient(iTarget, sMsg); SourceTV_KickClient(iTarget, sMsg);
ReplyToCommand(client, "SourceTV kicking spectator %d with reason %s", iTarget, sMsg); ReplyToCommand(client, "SourceTV kicking spectator %d with reason %s", iTarget, sMsg);
return Plugin_Handled; return Plugin_Handled;
}
public Action:Cmd_PrintToChat(client, args)
{
if (args < 2)
{
ReplyToCommand(client, "Usage: sm_specchatone <index> <message>");
return Plugin_Handled;
}
new String:sIndex[16], String:sMsg[1024];
GetCmdArg(1, sIndex, sizeof(sIndex));
StripQuotes(sIndex);
GetCmdArg(2, sMsg, sizeof(sMsg));
StripQuotes(sMsg);
new iTarget = StringToInt(sIndex);
SourceTV_PrintToChat(iTarget, "%s", sMsg);
ReplyToCommand(client, "SourceTV sending chat message to spectator %d: %s", iTarget, sMsg);
return Plugin_Handled;
} }

View File

@ -63,6 +63,12 @@
"linux" "65" "linux" "65"
} }
"CBaseClient::FireGameEvent"
{
"windows" "1"
"linux" "2"
}
"CBaseClient::Disconnect" "CBaseClient::Disconnect"
{ {
"linux" "16" "linux" "16"
@ -230,6 +236,12 @@
"linux" "56" "linux" "56"
} }
"CBaseClient::FireGameEvent"
{
"windows" "1"
"linux" "2"
}
"CBaseClient::Disconnect" "CBaseClient::Disconnect"
{ {
"linux" "14" "linux" "14"

View File

@ -393,6 +393,16 @@ native SourceTV_GetClientPassword(client, String:password[], maxlen);
*/ */
native SourceTV_KickClient(client, const String:sReason[]); native SourceTV_KickClient(client, const String:sReason[]);
/**
* Print a message to a single client's chat.
*
* @param client The spectator client index.
* @param format The format string.
* @param ... Variable number of format string arguments.
* @noreturn
* @error Invalid client index or not connected.
*/
native SourceTV_PrintToChat(client, const String:format[], any:...);
/** /**
* Called when a spectator wants to connect to the SourceTV server. * Called when a spectator wants to connect to the SourceTV server.
@ -520,5 +530,6 @@ public __ext_stvmngr_SetNTVOptional()
MarkNativeAsOptional("SourceTV_GetClientIP"); MarkNativeAsOptional("SourceTV_GetClientIP");
MarkNativeAsOptional("SourceTV_GetClientPassword"); MarkNativeAsOptional("SourceTV_GetClientPassword");
MarkNativeAsOptional("SourceTV_KickClient"); MarkNativeAsOptional("SourceTV_KickClient");
MarkNativeAsOptional("SourceTV_PrintToChat");
} }
#endif #endif