extensions/sdktools/voice.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Mon May 13 15:18:12 2013 -0400 (2013-05-13)
changeset 3913 a73cf1f26984
parent 3819 d17aed3d46bf
child 3942 7aaa00382627
permissions -rw-r--r--
Updated for latest hl2sdk-dota changes.
teame06@1245
     1
/**
teame06@1245
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
teame06@1245
     4
 * SourceMod SDKTools Extension
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
teame06@1245
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
ferret99gt@1468
    11
 *
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
teame06@1245
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
teame06@1245
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
teame06@1245
    28
 *
faluco@1247
    29
 * Version: $Id$
teame06@1245
    30
 */
teame06@1245
    31
teame06@1235
    32
#include <extension.h>
pred@2711
    33
#include <hooks.h>
teame06@1235
    34
teame06@1235
    35
#define SPEAK_NORMAL		0
teame06@1235
    36
#define SPEAK_MUTED			1
teame06@1235
    37
#define SPEAK_ALL			2
teame06@1235
    38
#define SPEAK_LISTENALL		4
ferret99gt@1468
    39
#define SPEAK_TEAM			8
ferret99gt@1468
    40
#define SPEAK_LISTENTEAM	16
dvander@2044
    41
#define LISTEN_DEFAULT		0
dvander@2044
    42
#define LISTEN_NO			1
dvander@2044
    43
#define LISTEN_YES			2
teame06@1235
    44
fyrenmoo@2796
    45
/* this enum needs to be in the order as the LISTEN_ defines above to keep
fyrenmoo@2796
    46
   the old broken SetClientListening functionality untouched */
fyrenmoo@2796
    47
enum ListenOverride
fyrenmoo@2796
    48
{
fyrenmoo@2796
    49
	Listen_Default,		/**< Leave it up to the game */
fyrenmoo@2796
    50
	Listen_No,			/**< Can't hear */
fyrenmoo@2796
    51
	Listen_Yes,			/**< Can hear */
fyrenmoo@2796
    52
};
fyrenmoo@2796
    53
teame06@1235
    54
size_t g_VoiceFlags[65];
dvander@2044
    55
size_t g_VoiceHookCount = 0;
fyrenmoo@2796
    56
ListenOverride g_VoiceMap[65][65];
fyrenmoo@2796
    57
bool g_ClientMutes[65][65];
teame06@1235
    58
teame06@1235
    59
SH_DECL_HOOK3(IVoiceServer, SetClientListening, SH_NOATTRIB, 0, bool, int, int, bool);
teame06@1235
    60
skamonkey@3913
    61
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3913
    62
SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, int, const CCommand &);
skamonkey@3913
    63
#elif SOURCE_ENGINE >= SE_ORANGEBOX
fyrenmoo@2796
    64
SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *, const CCommand &);
fyrenmoo@2796
    65
#else
fyrenmoo@2796
    66
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
fyrenmoo@2796
    67
#endif
fyrenmoo@2796
    68
datal30mb@3210
    69
bool DecHookCount()
dvander@2044
    70
{
dvander@2044
    71
	if (g_VoiceHookCount == 0)
dvander@2044
    72
	{
kyle@3819
    73
		SH_REMOVE_HOOK(IVoiceServer, SetClientListening, voiceserver, SH_MEMBER(&g_SdkTools, &SDKTools::OnSetClientListening), false);
dvander@2044
    74
		return true;
dvander@2044
    75
	}
dvander@2044
    76
dvander@2044
    77
	return false;
dvander@2044
    78
}
dvander@2044
    79
dvander@2044
    80
void IncHookCount()
dvander@2044
    81
{
dvander@2044
    82
	if (!g_VoiceHookCount++)
dvander@2044
    83
	{
kyle@3819
    84
		SH_ADD_HOOK(IVoiceServer, SetClientListening, voiceserver, SH_MEMBER(&g_SdkTools, &SDKTools::OnSetClientListening), false);
dvander@2044
    85
	}
dvander@2044
    86
}
dvander@2044
    87
dvander@2044
    88
void SDKTools::VoiceInit()
dvander@2044
    89
{
dvander@2044
    90
	memset(g_VoiceMap, 0, sizeof(g_VoiceMap));
fyrenmoo@2796
    91
	memset(g_ClientMutes, 0, sizeof(g_ClientMutes));
fyrenmoo@2796
    92
kyle@3819
    93
	SH_ADD_HOOK(IServerGameClients, ClientCommand, serverClients, SH_MEMBER(this, &SDKTools::OnClientCommand), true);
dvander@2044
    94
}
dvander@2044
    95
skamonkey@3913
    96
#if SOURCE_ENGINE == SE_DOTA
skamonkey@3913
    97
void SDKTools::OnClientCommand(int client, const CCommand &args)
skamonkey@3913
    98
{
skamonkey@3913
    99
#elif SOURCE_ENGINE >= SE_ORANGEBOX
fyrenmoo@2796
   100
void SDKTools::OnClientCommand(edict_t *pEntity, const CCommand &args)
fyrenmoo@2796
   101
{
skamonkey@3913
   102
	int client = IndexOfEdict(pEntity);
fyrenmoo@2796
   103
#else
fyrenmoo@2796
   104
void SDKTools::OnClientCommand(edict_t *pEntity)
fyrenmoo@2796
   105
{
fyrenmoo@2796
   106
	CCommand args;
skamonkey@3913
   107
	int client = IndexOfEdict(pEntity);
fyrenmoo@2796
   108
#endif
fyrenmoo@2796
   109
fyrenmoo@2796
   110
	if ((args.ArgC() > 1) && (stricmp(args.Arg(0), "vban") == 0))
fyrenmoo@2796
   111
	{
fyrenmoo@2796
   112
		for (int i = 1; (i < args.ArgC()) && (i < 3); i++)
fyrenmoo@2796
   113
		{
fyrenmoo@2796
   114
			unsigned long mask = 0;
dvander@2797
   115
			sscanf(args.Arg(i), "%p", (void**)&mask);
fyrenmoo@2796
   116
			
fyrenmoo@2796
   117
			for (int j = 0; j < 32; j++)
fyrenmoo@2796
   118
			{
fyrenmoo@2796
   119
				g_ClientMutes[client][1 + j + 32 * (i - 1)] = !!(mask & 1 << j);
fyrenmoo@2796
   120
			}
fyrenmoo@2796
   121
		}
fyrenmoo@2796
   122
	}
fyrenmoo@2796
   123
fyrenmoo@2796
   124
	RETURN_META(MRES_IGNORED);
fyrenmoo@2796
   125
}
fyrenmoo@2796
   126
teame06@1235
   127
bool SDKTools::OnSetClientListening(int iReceiver, int iSender, bool bListen)
teame06@1235
   128
{
fyrenmoo@2796
   129
	if (g_ClientMutes[iReceiver][iSender])
dvander@2044
   130
	{
dvander@2044
   131
		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, false));
dvander@2044
   132
	}
fyrenmoo@2796
   133
datal30mb@3211
   134
	if (g_VoiceFlags[iSender] & SPEAK_MUTED)
datal30mb@3211
   135
	{
datal30mb@3211
   136
		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, false));
datal30mb@3211
   137
	}
datal30mb@3211
   138
fyrenmoo@2796
   139
	if (g_VoiceMap[iReceiver][iSender] == Listen_No)
fyrenmoo@2796
   140
	{
fyrenmoo@2796
   141
		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, false));
fyrenmoo@2796
   142
	}
fyrenmoo@2796
   143
	else if (g_VoiceMap[iReceiver][iSender] == Listen_Yes)
dvander@2044
   144
	{
dvander@2044
   145
		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true));
dvander@2044
   146
	}
dvander@2044
   147
ferret99gt@1468
   148
	if ((g_VoiceFlags[iSender] & SPEAK_ALL) || (g_VoiceFlags[iReceiver] & SPEAK_LISTENALL))
teame06@1235
   149
	{
teame06@1235
   150
		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true));
teame06@1235
   151
	}
teame06@1235
   152
ferret99gt@1468
   153
	if ((g_VoiceFlags[iSender] & SPEAK_TEAM) || (g_VoiceFlags[iReceiver] & SPEAK_LISTENTEAM))
teame06@1235
   154
	{
ferret99gt@1468
   155
		IGamePlayer *pReceiver = playerhelpers->GetGamePlayer(iReceiver);
ferret99gt@1468
   156
		IGamePlayer *pSender = playerhelpers->GetGamePlayer(iSender);
ferret99gt@1468
   157
ferret99gt@1468
   158
		if (pReceiver && pSender && pReceiver->IsInGame() && pSender->IsInGame())
ferret99gt@1468
   159
		{
ferret99gt@1468
   160
			IPlayerInfo *pRInfo = pReceiver->GetPlayerInfo();
ferret99gt@1468
   161
			IPlayerInfo *pSInfo = pSender->GetPlayerInfo();
ferret99gt@1468
   162
ferret99gt@1468
   163
			if (pRInfo && pSInfo && pRInfo->GetTeamIndex() == pSInfo->GetTeamIndex())
ferret99gt@1468
   164
			{
ferret99gt@1468
   165
				RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true));
ferret99gt@1468
   166
			}
ferret99gt@1468
   167
		}
teame06@1235
   168
	}
teame06@1235
   169
teame06@1235
   170
	RETURN_META_VALUE(MRES_IGNORED, bListen);
teame06@1235
   171
}
teame06@1235
   172
teame06@1235
   173
void SDKTools::OnClientDisconnecting(int client)
teame06@1235
   174
{
pred@2711
   175
	g_Hooks.OnClientDisconnecting(client);
pred@2711
   176
dvander@2044
   177
	int max_clients = playerhelpers->GetMaxClients();
dvander@2044
   178
dvander@2044
   179
	if (g_VoiceHookCount == 0)
dvander@2044
   180
	{
dvander@2044
   181
		return;
dvander@2044
   182
	}
dvander@2044
   183
dvander@2044
   184
	/* This can probably be optimized more, but I doubt it's that much 
dvander@2044
   185
	 * of an actual bottleneck.
dvander@2044
   186
	 */
dvander@2044
   187
fyrenmoo@2796
   188
	/* Reset other clients who receive from or have muted this client */
dvander@2044
   189
	for (int i = 1; i <= max_clients; i++)
dvander@2044
   190
	{
dvander@2044
   191
		if (i == client)
dvander@2044
   192
		{
dvander@2045
   193
			continue;
dvander@2044
   194
		}
dvander@2044
   195
fyrenmoo@2796
   196
		g_ClientMutes[i][client] = false;
datal30mb@3210
   197
		g_ClientMutes[client][i] = false;
fyrenmoo@2796
   198
		
fyrenmoo@2796
   199
		if (g_VoiceMap[i][client] != Listen_Default)
dvander@2044
   200
		{
fyrenmoo@2796
   201
			g_VoiceMap[i][client] = Listen_Default;
dvander@2045
   202
			if (DecHookCount())
dvander@2045
   203
			{
fyrenmoo@3031
   204
				break;
dvander@2045
   205
			}
dvander@2044
   206
		}
datal30mb@3210
   207
		if (g_VoiceMap[client][i] != Listen_Default)
datal30mb@3210
   208
		{
datal30mb@3210
   209
			g_VoiceMap[client][i] = Listen_Default;
datal30mb@3210
   210
			if (DecHookCount())
datal30mb@3210
   211
			{
datal30mb@3210
   212
				break;
datal30mb@3210
   213
			}
datal30mb@3210
   214
		}
dvander@2044
   215
	}
dvander@2044
   216
teame06@1235
   217
	if (g_VoiceFlags[client])
ferret99gt@1468
   218
	{
datal30mb@3210
   219
		g_VoiceFlags[client] = SPEAK_NORMAL;
dvander@2044
   220
		DecHookCount();
teame06@1235
   221
	}
teame06@1235
   222
}
teame06@1235
   223
teame06@1235
   224
static cell_t SetClientListeningFlags(IPluginContext *pContext, const cell_t *params)
teame06@1235
   225
{
teame06@1235
   226
	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
teame06@1235
   227
	if (player == NULL)
teame06@1235
   228
	{
teame06@1235
   229
		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
dvander@2044
   230
	}
dvander@2044
   231
	else if (!player->IsConnected())
dvander@2044
   232
	{
teame06@1235
   233
		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
teame06@1235
   234
	}
teame06@1235
   235
teame06@1235
   236
	if (!params[2] && g_VoiceFlags[params[1]])
teame06@1235
   237
	{
dvander@2044
   238
		DecHookCount();
dvander@2044
   239
	}
dvander@2044
   240
	else if (!g_VoiceFlags[params[1]] && params[2])
dvander@2044
   241
	{
dvander@2044
   242
		IncHookCount();
teame06@1235
   243
	}
teame06@1235
   244
teame06@1235
   245
	g_VoiceFlags[params[1]] = params[2];
teame06@1235
   246
teame06@1235
   247
	return 1;
teame06@1235
   248
}
teame06@1235
   249
teame06@1235
   250
static cell_t GetClientListeningFlags(IPluginContext *pContext, const cell_t *params)
teame06@1235
   251
{
teame06@1235
   252
	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
teame06@1235
   253
	if (player == NULL)
teame06@1235
   254
	{
teame06@1235
   255
		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
dvander@2044
   256
	}
dvander@2044
   257
	else if (!player->IsConnected())
dvander@2044
   258
	{
teame06@1235
   259
		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
teame06@1235
   260
	}
teame06@1235
   261
teame06@1235
   262
	return g_VoiceFlags[params[1]];
teame06@1235
   263
}
teame06@1235
   264
teame06@1235
   265
static cell_t SetClientListening(IPluginContext *pContext, const cell_t *params)
teame06@1235
   266
{
dvander@2044
   267
	int r, s;
dvander@2044
   268
	IGamePlayer *player;
dvander@2044
   269
	
dvander@2044
   270
	player = playerhelpers->GetGamePlayer(params[1]);
dvander@2044
   271
	if (player == NULL)
dvander@2044
   272
	{
fyrenmoo@2796
   273
		return pContext->ThrowNativeError("Receiver client index %d is invalid", params[1]);
dvander@2044
   274
	}
dvander@2044
   275
	else if (!player->IsConnected())
dvander@2044
   276
	{
fyrenmoo@2796
   277
		return pContext->ThrowNativeError("Receiver client %d is not connected", params[1]);
dvander@2044
   278
	}
dvander@2044
   279
dvander@2044
   280
	player = playerhelpers->GetGamePlayer(params[2]);
teame06@1235
   281
	if (player == NULL)
teame06@1235
   282
	{
fyrenmoo@2796
   283
		return pContext->ThrowNativeError("Sender client index %d is invalid", params[2]);
dvander@2044
   284
	}
dvander@2044
   285
	else if (!player->IsConnected())
dvander@2044
   286
	{
fyrenmoo@2796
   287
		return pContext->ThrowNativeError("Sender client %d is not connected", params[2]);
teame06@1235
   288
	}
teame06@1235
   289
dvander@2044
   290
	r = params[1];
dvander@2044
   291
	s = params[2];
dvander@2044
   292
	
fyrenmoo@2796
   293
	if (g_VoiceMap[r][s] == Listen_Default && params[3] != Listen_Default)
dvander@2044
   294
	{
fyrenmoo@2796
   295
		g_VoiceMap[r][s] = (ListenOverride) params[3];
dvander@2044
   296
		IncHookCount();
dvander@2044
   297
	}
fyrenmoo@2796
   298
	else if (g_VoiceMap[r][s] != Listen_Default && params[3] == Listen_Default)
dvander@2044
   299
	{
fyrenmoo@2796
   300
		g_VoiceMap[r][s] = (ListenOverride) params[3];
dvander@2044
   301
		DecHookCount();
dvander@2044
   302
	}
dvander@2044
   303
	else
dvander@2044
   304
	{
fyrenmoo@2796
   305
		g_VoiceMap[r][s] = (ListenOverride) params[3];
dvander@2044
   306
	}
teame06@1235
   307
dvander@2044
   308
	return 1;
teame06@1235
   309
}
teame06@1235
   310
teame06@1235
   311
static cell_t GetClientListening(IPluginContext *pContext, const cell_t *params)
teame06@1235
   312
{
dvander@2044
   313
	IGamePlayer *player;
dvander@2044
   314
dvander@2044
   315
	player = playerhelpers->GetGamePlayer(params[1]);
teame06@1235
   316
	if (player == NULL)
teame06@1235
   317
	{
fyrenmoo@2796
   318
		return pContext->ThrowNativeError("Receiver client index %d is invalid", params[1]);
dvander@2044
   319
	}
dvander@2044
   320
	else if (!player->IsConnected())
dvander@2044
   321
	{
fyrenmoo@2796
   322
		return pContext->ThrowNativeError("Receiver client %d is not connected", params[1]);
teame06@1235
   323
	}
teame06@1235
   324
dvander@2044
   325
	player = playerhelpers->GetGamePlayer(params[2]);
dvander@2044
   326
	if (player == NULL)
dvander@2044
   327
	{
fyrenmoo@2796
   328
		return pContext->ThrowNativeError("Sender client index %d is invalid", params[2]);
dvander@2044
   329
	}
dvander@2044
   330
	else if (!player->IsConnected())
dvander@2044
   331
	{
fyrenmoo@2796
   332
		return pContext->ThrowNativeError("Sender client %d is not connected", params[2]);
dvander@2044
   333
	}
dvander@2044
   334
dvander@2044
   335
	return g_VoiceMap[params[1]][params[2]];
teame06@1235
   336
}
teame06@1235
   337
fyrenmoo@2796
   338
static cell_t IsClientMuted(IPluginContext *pContext, const cell_t *params)
fyrenmoo@2796
   339
{
fyrenmoo@2796
   340
	IGamePlayer *player;
fyrenmoo@2796
   341
fyrenmoo@2796
   342
	player = playerhelpers->GetGamePlayer(params[1]);
fyrenmoo@2796
   343
	if (player == NULL)
fyrenmoo@2796
   344
	{
fyrenmoo@2796
   345
		return pContext->ThrowNativeError("Muter client index %d is invalid", params[1]);
fyrenmoo@2796
   346
	}
fyrenmoo@2796
   347
	else if (!player->IsConnected())
fyrenmoo@2796
   348
	{
fyrenmoo@2796
   349
		return pContext->ThrowNativeError("Muter client %d is not connected", params[1]);
fyrenmoo@2796
   350
	}
fyrenmoo@2796
   351
fyrenmoo@2796
   352
	player = playerhelpers->GetGamePlayer(params[2]);
fyrenmoo@2796
   353
	if (player == NULL)
fyrenmoo@2796
   354
	{
fyrenmoo@2796
   355
		return pContext->ThrowNativeError("Mutee client index %d is invalid", params[2]);
fyrenmoo@2796
   356
	}
fyrenmoo@2796
   357
	else if (!player->IsConnected())
fyrenmoo@2796
   358
	{
fyrenmoo@2796
   359
		return pContext->ThrowNativeError("Mutee client %d is not connected", params[2]);
fyrenmoo@2796
   360
	}
fyrenmoo@2796
   361
fyrenmoo@2796
   362
	return g_ClientMutes[params[1]][params[2]];
fyrenmoo@2796
   363
}
fyrenmoo@2796
   364
ferret99gt@1468
   365
sp_nativeinfo_t g_VoiceNatives[] =
teame06@1235
   366
{
teame06@1235
   367
	{"SetClientListeningFlags",		SetClientListeningFlags},
teame06@1235
   368
	{"GetClientListeningFlags",		GetClientListeningFlags},
teame06@1235
   369
	{"SetClientListening",			SetClientListening},
teame06@1235
   370
	{"GetClientListening",			GetClientListening},
fyrenmoo@2796
   371
	{"SetListenOverride",			SetClientListening},
fyrenmoo@2796
   372
	{"GetListenOverride",			GetClientListening},
fyrenmoo@2796
   373
	{"IsClientMuted",				IsClientMuted},
teame06@1235
   374
	{NULL,							NULL},
teame06@1235
   375
};