Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
7.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "voice_gamemgr.h"
  9. #include <string.h>
  10. #include <stdarg.h>
  11. #include <assert.h>
  12. #include "player.h"
  13. #include "ivoiceserver.h"
  14. #include "usermessages.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. #define UPDATE_INTERVAL 0.3
  18. // These are stored off as CVoiceGameMgr is created and deleted.
  19. CPlayerBitVec g_PlayerModEnable; // Set to 1 for each player if the player wants to use voice in this mod.
  20. // (If it's zero, then the server reports that the game rules are saying the
  21. // player can't hear anyone).
  22. CPlayerBitVec g_BanMasks[VOICE_MAX_PLAYERS]; // Tells which players don't want to hear each other.
  23. // These are indexed as clients and each bit represents a client
  24. // (so player entity is bit+1).
  25. CPlayerBitVec g_SentGameRulesMasks[VOICE_MAX_PLAYERS]; // These store the masks we last sent to each client so we can determine if
  26. CPlayerBitVec g_SentBanMasks[VOICE_MAX_PLAYERS]; // we need to resend them.
  27. CPlayerBitVec g_bWantModEnable;
  28. ConVar voice_serverdebug( "voice_serverdebug", "0" );
  29. // Set game rules to allow all clients to talk to each other.
  30. // Muted players still can't talk to each other.
  31. ConVar sv_alltalk( "sv_alltalk", "0", FCVAR_NOTIFY | FCVAR_REPLICATED, "Players can hear all other players, no team restrictions" );
  32. CVoiceGameMgr g_VoiceGameMgr;
  33. // ------------------------------------------------------------------------ //
  34. // Static helpers.
  35. // ------------------------------------------------------------------------ //
  36. // Find a player with a case-insensitive name search.
  37. #if 0
  38. static CBasePlayer* FindPlayerByName(const char *pTestName)
  39. {
  40. for(int i=1; i <= gpGlobals->maxClients; i++)
  41. {
  42. edict_t *pEdict = engine->PEntityOfEntIndex(i);
  43. if(pEdict)
  44. {
  45. CBaseEntity *pEnt = CBaseEntity::Instance(pEdict);
  46. if(pEnt && pEnt->IsPlayer())
  47. {
  48. const char *pNetName = STRING(pEnt->GetEntityName());
  49. if(stricmp(pNetName, pTestName) == 0)
  50. {
  51. return (CBasePlayer*)pEnt;
  52. }
  53. }
  54. }
  55. }
  56. return NULL;
  57. }
  58. #endif
  59. static void VoiceServerDebug( const char *pFmt, ... )
  60. {
  61. char msg[4096];
  62. va_list marker;
  63. if( !voice_serverdebug.GetInt() )
  64. return;
  65. va_start( marker, pFmt );
  66. _vsnprintf( msg, sizeof(msg), pFmt, marker );
  67. va_end( marker );
  68. Msg( "%s", msg );
  69. }
  70. CVoiceGameMgr* GetVoiceGameMgr()
  71. {
  72. return &g_VoiceGameMgr;
  73. }
  74. // ------------------------------------------------------------------------ //
  75. // CVoiceGameMgr.
  76. // ------------------------------------------------------------------------ //
  77. CVoiceGameMgr::CVoiceGameMgr()
  78. {
  79. m_UpdateInterval = 0;
  80. m_nMaxPlayers = 0;
  81. m_iProximityDistance = -1;
  82. }
  83. CVoiceGameMgr::~CVoiceGameMgr()
  84. {
  85. }
  86. bool CVoiceGameMgr::Init(
  87. IVoiceGameMgrHelper *pHelper,
  88. int maxClients)
  89. {
  90. m_pHelper = pHelper;
  91. m_nMaxPlayers = VOICE_MAX_PLAYERS < maxClients ? VOICE_MAX_PLAYERS : maxClients;
  92. return true;
  93. }
  94. void CVoiceGameMgr::SetHelper(IVoiceGameMgrHelper *pHelper)
  95. {
  96. m_pHelper = pHelper;
  97. }
  98. void CVoiceGameMgr::Update(double frametime)
  99. {
  100. // Only update periodically.
  101. m_UpdateInterval += frametime;
  102. if(m_UpdateInterval < UPDATE_INTERVAL)
  103. return;
  104. UpdateMasks();
  105. }
  106. void CVoiceGameMgr::ClientConnected(struct edict_t *pEdict)
  107. {
  108. int index = ENTINDEX(pEdict) - 1;
  109. // Clear out everything we use for deltas on this guy.
  110. g_bWantModEnable[index] = true;
  111. g_SentGameRulesMasks[index].Init(0);
  112. g_SentBanMasks[index].Init(0);
  113. }
  114. bool CVoiceGameMgr::ClientCommand( CBasePlayer *pPlayer, const CCommand &args )
  115. {
  116. int playerClientIndex = pPlayer->entindex() - 1;
  117. if(playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers)
  118. {
  119. VoiceServerDebug( "CVoiceGameMgr::ClientCommand: cmd %s from invalid client (%d)\n", args[0], playerClientIndex );
  120. return true;
  121. }
  122. bool bBan = stricmp( args[0], "vban" ) == 0;
  123. if( bBan && args.ArgC() >= 2 )
  124. {
  125. for(int i=1; i < args.ArgC(); i++)
  126. {
  127. uint32 mask = 0;
  128. sscanf( args[i], "%x", &mask);
  129. if( i <= VOICE_MAX_PLAYERS_DW )
  130. {
  131. VoiceServerDebug( "CVoiceGameMgr::ClientCommand: vban (0x%x) from %d\n", mask, playerClientIndex );
  132. g_BanMasks[playerClientIndex].SetDWord(i-1, mask);
  133. }
  134. else
  135. {
  136. VoiceServerDebug( "CVoiceGameMgr::ClientCommand: invalid index (%d)\n", i );
  137. }
  138. }
  139. // Force it to update the masks now.
  140. //UpdateMasks();
  141. return true;
  142. }
  143. else if(stricmp( args[0], "VModEnable") == 0 && args.ArgC() >= 2)
  144. {
  145. VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi( args[1] ) );
  146. g_PlayerModEnable[playerClientIndex] = !!atoi( args[1] );
  147. g_bWantModEnable[playerClientIndex] = false;
  148. //UpdateMasks();
  149. return true;
  150. }
  151. else
  152. {
  153. return false;
  154. }
  155. }
  156. void CVoiceGameMgr::UpdateMasks()
  157. {
  158. m_UpdateInterval = 0;
  159. bool bAllTalk = !!sv_alltalk.GetInt();
  160. for(int iClient=0; iClient < m_nMaxPlayers; iClient++)
  161. {
  162. CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1);
  163. if(!pEnt || !pEnt->IsPlayer())
  164. continue;
  165. CBasePlayer *pPlayer = (CBasePlayer*)pEnt;
  166. CSingleUserRecipientFilter user( pPlayer );
  167. // Request the state of their "VModEnable" cvar.
  168. if(g_bWantModEnable[iClient])
  169. {
  170. UserMessageBegin( user, "RequestState" );
  171. MessageEnd();
  172. // Since this is reliable, only send it once
  173. g_bWantModEnable[iClient] = false;
  174. }
  175. CPlayerBitVec gameRulesMask;
  176. CPlayerBitVec ProximityMask;
  177. bool bProximity = false;
  178. if( g_PlayerModEnable[iClient] )
  179. {
  180. // Build a mask of who they can hear based on the game rules.
  181. for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++)
  182. {
  183. CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient+1);
  184. if(pEnt && pEnt->IsPlayer() &&
  185. (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt, bProximity )) )
  186. {
  187. gameRulesMask[iOtherClient] = true;
  188. ProximityMask[iOtherClient] = bProximity;
  189. }
  190. }
  191. }
  192. // If this is different from what the client has, send an update.
  193. if(gameRulesMask != g_SentGameRulesMasks[iClient] ||
  194. g_BanMasks[iClient] != g_SentBanMasks[iClient])
  195. {
  196. g_SentGameRulesMasks[iClient] = gameRulesMask;
  197. g_SentBanMasks[iClient] = g_BanMasks[iClient];
  198. UserMessageBegin( user, "VoiceMask" );
  199. int dw;
  200. for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++)
  201. {
  202. WRITE_LONG(gameRulesMask.GetDWord(dw));
  203. WRITE_LONG(g_BanMasks[iClient].GetDWord(dw));
  204. }
  205. WRITE_BYTE( !!g_PlayerModEnable[iClient] );
  206. MessageEnd();
  207. }
  208. // Tell the engine.
  209. for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++)
  210. {
  211. bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient];
  212. g_pVoiceServer->SetClientListening( iClient+1, iOtherClient+1, bCanHear );
  213. if ( bCanHear )
  214. {
  215. g_pVoiceServer->SetClientProximity( iClient+1, iOtherClient+1, !!ProximityMask[iOtherClient] );
  216. }
  217. }
  218. }
  219. }
  220. bool CVoiceGameMgr::IsPlayerIgnoringPlayer( int iTalker, int iListener )
  221. {
  222. return !!g_BanMasks[iListener-1][iTalker-1];
  223. }
  224. void CVoiceGameMgr::SetProximityDistance( int iDistance )
  225. {
  226. m_iProximityDistance = iDistance;
  227. }
  228. bool CVoiceGameMgr::CheckProximity( int iDistance )
  229. {
  230. if ( m_iProximityDistance >= iDistance )
  231. return true;
  232. return false;
  233. }