teame06@1245: /** teame06@1245: * vim: set ts=4 : ds@1330: * ============================================================================= teame06@1245: * SourceMod SDKTools Extension ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= teame06@1245: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. ferret99gt@1468: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. teame06@1245: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . teame06@1245: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . teame06@1245: * faluco@1247: * Version: $Id$ teame06@1245: */ teame06@1245: teame06@1235: #include pred@2711: #include teame06@1235: teame06@1235: #define SPEAK_NORMAL 0 teame06@1235: #define SPEAK_MUTED 1 teame06@1235: #define SPEAK_ALL 2 teame06@1235: #define SPEAK_LISTENALL 4 ferret99gt@1468: #define SPEAK_TEAM 8 ferret99gt@1468: #define SPEAK_LISTENTEAM 16 dvander@2044: #define LISTEN_DEFAULT 0 dvander@2044: #define LISTEN_NO 1 dvander@2044: #define LISTEN_YES 2 teame06@1235: fyrenmoo@2796: /* this enum needs to be in the order as the LISTEN_ defines above to keep fyrenmoo@2796: the old broken SetClientListening functionality untouched */ fyrenmoo@2796: enum ListenOverride fyrenmoo@2796: { fyrenmoo@2796: Listen_Default, /**< Leave it up to the game */ fyrenmoo@2796: Listen_No, /**< Can't hear */ fyrenmoo@2796: Listen_Yes, /**< Can hear */ fyrenmoo@2796: }; fyrenmoo@2796: teame06@1235: size_t g_VoiceFlags[65]; dvander@2044: size_t g_VoiceHookCount = 0; fyrenmoo@2796: int g_ClientOverrides[65]; fyrenmoo@2796: ListenOverride g_VoiceMap[65][65]; fyrenmoo@2796: bool g_ClientMutes[65][65]; teame06@1235: teame06@1235: SH_DECL_HOOK3(IVoiceServer, SetClientListening, SH_NOATTRIB, 0, bool, int, int, bool); teame06@1235: fyrenmoo@2796: #if SOURCE_ENGINE >= SE_ORANGEBOX fyrenmoo@2796: SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *, const CCommand &); fyrenmoo@2796: #else fyrenmoo@2796: SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *); fyrenmoo@2796: #endif fyrenmoo@2796: dvander@2044: bool DecHookCount(int amount = 1); dvander@2044: bool DecHookCount(int amount) dvander@2044: { dvander@2044: g_VoiceHookCount -= amount; dvander@2044: if (g_VoiceHookCount == 0) dvander@2044: { dvander@2044: SH_REMOVE_HOOK_MEMFUNC(IVoiceServer, SetClientListening, voiceserver, &g_SdkTools, &SDKTools::OnSetClientListening, false); dvander@2044: return true; dvander@2044: } dvander@2044: dvander@2044: return false; dvander@2044: } dvander@2044: dvander@2044: void IncHookCount() dvander@2044: { dvander@2044: if (!g_VoiceHookCount++) dvander@2044: { dvander@2044: SH_ADD_HOOK_MEMFUNC(IVoiceServer, SetClientListening, voiceserver, &g_SdkTools, &SDKTools::OnSetClientListening, false); dvander@2044: } dvander@2044: } dvander@2044: dvander@2044: void SDKTools::VoiceInit() dvander@2044: { dvander@2044: memset(g_VoiceMap, 0, sizeof(g_VoiceMap)); fyrenmoo@2796: memset(g_ClientOverrides, 0, sizeof(g_ClientOverrides)); fyrenmoo@2796: memset(g_ClientMutes, 0, sizeof(g_ClientMutes)); fyrenmoo@2796: fyrenmoo@2796: SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &SDKTools::OnClientCommand, true); dvander@2044: } dvander@2044: fyrenmoo@2796: #if SOURCE_ENGINE >= SE_ORANGEBOX fyrenmoo@2796: void SDKTools::OnClientCommand(edict_t *pEntity, const CCommand &args) fyrenmoo@2796: { fyrenmoo@2796: #else fyrenmoo@2796: void SDKTools::OnClientCommand(edict_t *pEntity) fyrenmoo@2796: { fyrenmoo@2796: CCommand args; fyrenmoo@2796: #endif fyrenmoo@2796: int client = IndexOfEdict(pEntity); fyrenmoo@2796: fyrenmoo@2796: if ((args.ArgC() > 1) && (stricmp(args.Arg(0), "vban") == 0)) fyrenmoo@2796: { fyrenmoo@2796: for (int i = 1; (i < args.ArgC()) && (i < 3); i++) fyrenmoo@2796: { fyrenmoo@2796: unsigned long mask = 0; fyrenmoo@2796: sscanf(args[i], "%p", (void**)&mask); fyrenmoo@2796: fyrenmoo@2796: for (int j = 0; j < 32; j++) fyrenmoo@2796: { fyrenmoo@2796: g_ClientMutes[client][1 + j + 32 * (i - 1)] = !!(mask & 1 << j); fyrenmoo@2796: } fyrenmoo@2796: } fyrenmoo@2796: } fyrenmoo@2796: fyrenmoo@2796: RETURN_META(MRES_IGNORED); fyrenmoo@2796: } fyrenmoo@2796: fyrenmoo@2796: teame06@1235: bool SDKTools::OnSetClientListening(int iReceiver, int iSender, bool bListen) teame06@1235: { fyrenmoo@2796: if (g_ClientMutes[iReceiver][iSender]) dvander@2044: { dvander@2044: RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, false)); dvander@2044: } fyrenmoo@2796: fyrenmoo@2796: if (g_VoiceMap[iReceiver][iSender] == Listen_No) fyrenmoo@2796: { fyrenmoo@2796: RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, false)); fyrenmoo@2796: } fyrenmoo@2796: else if (g_VoiceMap[iReceiver][iSender] == Listen_Yes) dvander@2044: { dvander@2044: RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true)); dvander@2044: } dvander@2044: ferret99gt@1468: if (g_VoiceFlags[iSender] & SPEAK_MUTED) teame06@1235: { teame06@1235: RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, false)); teame06@1235: } teame06@1235: ferret99gt@1468: if ((g_VoiceFlags[iSender] & SPEAK_ALL) || (g_VoiceFlags[iReceiver] & SPEAK_LISTENALL)) teame06@1235: { teame06@1235: RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true)); teame06@1235: } teame06@1235: ferret99gt@1468: if ((g_VoiceFlags[iSender] & SPEAK_TEAM) || (g_VoiceFlags[iReceiver] & SPEAK_LISTENTEAM)) teame06@1235: { ferret99gt@1468: IGamePlayer *pReceiver = playerhelpers->GetGamePlayer(iReceiver); ferret99gt@1468: IGamePlayer *pSender = playerhelpers->GetGamePlayer(iSender); ferret99gt@1468: ferret99gt@1468: if (pReceiver && pSender && pReceiver->IsInGame() && pSender->IsInGame()) ferret99gt@1468: { ferret99gt@1468: IPlayerInfo *pRInfo = pReceiver->GetPlayerInfo(); ferret99gt@1468: IPlayerInfo *pSInfo = pSender->GetPlayerInfo(); ferret99gt@1468: ferret99gt@1468: if (pRInfo && pSInfo && pRInfo->GetTeamIndex() == pSInfo->GetTeamIndex()) ferret99gt@1468: { ferret99gt@1468: RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true)); ferret99gt@1468: } ferret99gt@1468: } teame06@1235: } teame06@1235: teame06@1235: RETURN_META_VALUE(MRES_IGNORED, bListen); teame06@1235: } teame06@1235: teame06@1235: void SDKTools::OnClientDisconnecting(int client) teame06@1235: { pred@2711: g_Hooks.OnClientDisconnecting(client); pred@2711: dvander@2044: int max_clients = playerhelpers->GetMaxClients(); dvander@2044: dvander@2044: if (g_VoiceHookCount == 0) dvander@2044: { dvander@2044: return; dvander@2044: } dvander@2044: dvander@2044: /* This can probably be optimized more, but I doubt it's that much dvander@2044: * of an actual bottleneck. dvander@2044: */ dvander@2044: fyrenmoo@2796: /* Reset other clients who receive from or have muted this client */ dvander@2044: for (int i = 1; i <= max_clients; i++) dvander@2044: { dvander@2044: if (i == client) dvander@2044: { dvander@2045: continue; dvander@2044: } dvander@2044: fyrenmoo@2796: g_ClientMutes[i][client] = false; fyrenmoo@2796: fyrenmoo@2796: if (g_VoiceMap[i][client] != Listen_Default) dvander@2044: { fyrenmoo@2796: g_VoiceMap[i][client] = Listen_Default; dvander@2045: if (DecHookCount()) dvander@2045: { dvander@2045: return; dvander@2045: } dvander@2044: } dvander@2044: } dvander@2044: fyrenmoo@2796: /* Reset this client's mutes, just in case */ fyrenmoo@2796: memset(&g_ClientMutes[client], 0, sizeof(int) * 65); fyrenmoo@2796: fyrenmoo@2796: /* Reset other clients who send to this client */ fyrenmoo@2796: if (g_ClientOverrides[client] > 0) dvander@2044: { fyrenmoo@2796: DecHookCount(g_ClientOverrides[client]); fyrenmoo@2796: g_ClientOverrides[client] = 0; fyrenmoo@2796: memset(&g_VoiceMap[client], false, sizeof(ListenOverride) * 65); fyrenmoo@2796: memset(&g_ClientMutes[client], false, sizeof(bool) * 65); dvander@2044: } dvander@2044: teame06@1235: if (g_VoiceFlags[client]) ferret99gt@1468: { teame06@1235: g_VoiceFlags[client] = 0; dvander@2044: DecHookCount(); teame06@1235: } teame06@1235: } teame06@1235: teame06@1235: static cell_t SetClientListeningFlags(IPluginContext *pContext, const cell_t *params) teame06@1235: { teame06@1235: IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]); teame06@1235: if (player == NULL) teame06@1235: { teame06@1235: return pContext->ThrowNativeError("Client index %d is invalid", params[1]); dvander@2044: } dvander@2044: else if (!player->IsConnected()) dvander@2044: { teame06@1235: return pContext->ThrowNativeError("Client %d is not connected", params[1]); teame06@1235: } teame06@1235: teame06@1235: if (!params[2] && g_VoiceFlags[params[1]]) teame06@1235: { dvander@2044: DecHookCount(); dvander@2044: } dvander@2044: else if (!g_VoiceFlags[params[1]] && params[2]) dvander@2044: { dvander@2044: IncHookCount(); teame06@1235: } teame06@1235: teame06@1235: g_VoiceFlags[params[1]] = params[2]; teame06@1235: teame06@1235: return 1; teame06@1235: } teame06@1235: teame06@1235: static cell_t GetClientListeningFlags(IPluginContext *pContext, const cell_t *params) teame06@1235: { teame06@1235: IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]); teame06@1235: if (player == NULL) teame06@1235: { teame06@1235: return pContext->ThrowNativeError("Client index %d is invalid", params[1]); dvander@2044: } dvander@2044: else if (!player->IsConnected()) dvander@2044: { teame06@1235: return pContext->ThrowNativeError("Client %d is not connected", params[1]); teame06@1235: } teame06@1235: teame06@1235: return g_VoiceFlags[params[1]]; teame06@1235: } teame06@1235: teame06@1235: static cell_t SetClientListening(IPluginContext *pContext, const cell_t *params) teame06@1235: { dvander@2044: int r, s; dvander@2044: IGamePlayer *player; dvander@2044: dvander@2044: player = playerhelpers->GetGamePlayer(params[1]); dvander@2044: if (player == NULL) dvander@2044: { fyrenmoo@2796: return pContext->ThrowNativeError("Receiver client index %d is invalid", params[1]); dvander@2044: } dvander@2044: else if (!player->IsConnected()) dvander@2044: { fyrenmoo@2796: return pContext->ThrowNativeError("Receiver client %d is not connected", params[1]); dvander@2044: } dvander@2044: dvander@2044: player = playerhelpers->GetGamePlayer(params[2]); teame06@1235: if (player == NULL) teame06@1235: { fyrenmoo@2796: return pContext->ThrowNativeError("Sender client index %d is invalid", params[2]); dvander@2044: } dvander@2044: else if (!player->IsConnected()) dvander@2044: { fyrenmoo@2796: return pContext->ThrowNativeError("Sender client %d is not connected", params[2]); teame06@1235: } teame06@1235: dvander@2044: r = params[1]; dvander@2044: s = params[2]; dvander@2044: fyrenmoo@2796: if (g_VoiceMap[r][s] == Listen_Default && params[3] != Listen_Default) dvander@2044: { fyrenmoo@2796: g_VoiceMap[r][s] = (ListenOverride) params[3]; fyrenmoo@2796: g_ClientOverrides[r]++; dvander@2044: IncHookCount(); dvander@2044: } fyrenmoo@2796: else if (g_VoiceMap[r][s] != Listen_Default && params[3] == Listen_Default) dvander@2044: { fyrenmoo@2796: g_VoiceMap[r][s] = (ListenOverride) params[3]; fyrenmoo@2796: g_ClientOverrides[r]--; dvander@2044: DecHookCount(); dvander@2044: } dvander@2044: else dvander@2044: { fyrenmoo@2796: g_VoiceMap[r][s] = (ListenOverride) params[3]; dvander@2044: } teame06@1235: dvander@2044: return 1; teame06@1235: } teame06@1235: teame06@1235: static cell_t GetClientListening(IPluginContext *pContext, const cell_t *params) teame06@1235: { dvander@2044: IGamePlayer *player; dvander@2044: dvander@2044: player = playerhelpers->GetGamePlayer(params[1]); teame06@1235: if (player == NULL) teame06@1235: { fyrenmoo@2796: return pContext->ThrowNativeError("Receiver client index %d is invalid", params[1]); dvander@2044: } dvander@2044: else if (!player->IsConnected()) dvander@2044: { fyrenmoo@2796: return pContext->ThrowNativeError("Receiver client %d is not connected", params[1]); teame06@1235: } teame06@1235: dvander@2044: player = playerhelpers->GetGamePlayer(params[2]); dvander@2044: if (player == NULL) dvander@2044: { fyrenmoo@2796: return pContext->ThrowNativeError("Sender client index %d is invalid", params[2]); dvander@2044: } dvander@2044: else if (!player->IsConnected()) dvander@2044: { fyrenmoo@2796: return pContext->ThrowNativeError("Sender client %d is not connected", params[2]); dvander@2044: } dvander@2044: dvander@2044: return g_VoiceMap[params[1]][params[2]]; teame06@1235: } teame06@1235: fyrenmoo@2796: static cell_t IsClientMuted(IPluginContext *pContext, const cell_t *params) fyrenmoo@2796: { fyrenmoo@2796: IGamePlayer *player; fyrenmoo@2796: fyrenmoo@2796: player = playerhelpers->GetGamePlayer(params[1]); fyrenmoo@2796: if (player == NULL) fyrenmoo@2796: { fyrenmoo@2796: return pContext->ThrowNativeError("Muter client index %d is invalid", params[1]); fyrenmoo@2796: } fyrenmoo@2796: else if (!player->IsConnected()) fyrenmoo@2796: { fyrenmoo@2796: return pContext->ThrowNativeError("Muter client %d is not connected", params[1]); fyrenmoo@2796: } fyrenmoo@2796: fyrenmoo@2796: player = playerhelpers->GetGamePlayer(params[2]); fyrenmoo@2796: if (player == NULL) fyrenmoo@2796: { fyrenmoo@2796: return pContext->ThrowNativeError("Mutee client index %d is invalid", params[2]); fyrenmoo@2796: } fyrenmoo@2796: else if (!player->IsConnected()) fyrenmoo@2796: { fyrenmoo@2796: return pContext->ThrowNativeError("Mutee client %d is not connected", params[2]); fyrenmoo@2796: } fyrenmoo@2796: fyrenmoo@2796: return g_ClientMutes[params[1]][params[2]]; fyrenmoo@2796: } fyrenmoo@2796: ferret99gt@1468: sp_nativeinfo_t g_VoiceNatives[] = teame06@1235: { teame06@1235: {"SetClientListeningFlags", SetClientListeningFlags}, teame06@1235: {"GetClientListeningFlags", GetClientListeningFlags}, teame06@1235: {"SetClientListening", SetClientListening}, teame06@1235: {"GetClientListening", GetClientListening}, fyrenmoo@2796: {"SetListenOverride", SetClientListening}, fyrenmoo@2796: {"GetListenOverride", GetClientListening}, fyrenmoo@2796: {"IsClientMuted", IsClientMuted}, teame06@1235: {NULL, NULL}, teame06@1235: };