Counter Strike : Global Offensive Source Code
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.

257 lines
7.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Provides an interface to enable positional audio support in Mumble
  4. //
  5. //===========================================================================//
  6. #if defined( WIN32 ) && !defined( _X360 )
  7. #define WIN32_LEAN_AND_MEAN
  8. #include <windows.h>
  9. #elif defined( POSIX )
  10. #include <sys/mman.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #endif
  15. #include "cbase.h"
  16. #include "shareddefs.h"
  17. #include "view.h"
  18. #include "mumble.h"
  19. #if !defined( _X360 ) && !defined( NO_STEAM )
  20. #include "steam/isteamuser.h"
  21. #include "steam/steam_api.h"
  22. #endif
  23. const char *COM_GetModDirectory(); // return the mod dir (rather than the complete -game param, which can be a path)
  24. struct MumbleSharedMemory_t
  25. {
  26. #ifdef WIN32
  27. uint32 uiVersion;
  28. ulong uiTick;
  29. #else
  30. uint32_t uiVersion;
  31. uint32_t uiTick;
  32. #endif
  33. float fAvatarPosition[3];
  34. float fAvatarFront[3];
  35. float fAvatarTop[3];
  36. wchar_t name[256];
  37. float fCameraPosition[3];
  38. float fCameraFront[3];
  39. float fCameraTop[3];
  40. wchar_t identity[256];
  41. #ifdef WIN32
  42. uint32 context_len;
  43. #else
  44. uint32_t context_len;
  45. #endif
  46. unsigned char context[256];
  47. wchar_t description[2048];
  48. };
  49. MumbleSharedMemory_t *g_pMumbleMemory = NULL;
  50. #ifdef WIN32
  51. HANDLE g_hMapObject = NULL;
  52. #endif
  53. ConVar sv_mumble_positionalaudio( "sv_mumble_positionalaudio", "1", FCVAR_REPLICATED, "Allows players using Mumble to have support for positional audio." );
  54. //-----------------------------------------------------------------------------
  55. // Singleton
  56. //-----------------------------------------------------------------------------
  57. static CMumbleSystem g_MumbleSystem;
  58. IGameSystem *MumbleSystem()
  59. {
  60. return &g_MumbleSystem;
  61. }
  62. bool CMumbleSystem::Init()
  63. {
  64. m_bHasSetPlayerUniqueId = false;
  65. m_nTeamSetInUniqueId = 0;
  66. m_szSteamIDCurrentServer[0] = '\0';
  67. m_cubSteamIDCurrentServer = 0;
  68. ListenForGameEvent( "server_spawn" );
  69. return true;
  70. }
  71. void CMumbleSystem::LevelInitPostEntity()
  72. {
  73. if ( g_pMumbleMemory )
  74. return;
  75. #if defined( WIN32 ) && !defined( _X360 )
  76. g_hMapObject = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink" );
  77. if ( g_hMapObject == NULL )
  78. return;
  79. g_pMumbleMemory = (MumbleSharedMemory_t *) MapViewOfFile( g_hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(MumbleSharedMemory_t) );
  80. if ( g_pMumbleMemory == NULL )
  81. {
  82. CloseHandle( g_hMapObject );
  83. g_hMapObject = NULL;
  84. return;
  85. }
  86. #elif defined( POSIX )
  87. char memname[256];
  88. V_sprintf_safe( memname, "/MumbleLink.%d", getuid() );
  89. int shmfd = shm_open( memname, O_RDWR, S_IRUSR | S_IWUSR );
  90. if ( shmfd < 0 )
  91. {
  92. return;
  93. }
  94. g_pMumbleMemory = (MumbleSharedMemory_t *)( mmap( NULL, sizeof(struct MumbleSharedMemory_t), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd,0 ) );
  95. if ( g_pMumbleMemory == (void *)(-1) )
  96. {
  97. g_pMumbleMemory = NULL;
  98. return;
  99. }
  100. #endif
  101. }
  102. void CMumbleSystem::LevelShutdownPreEntity()
  103. {
  104. #if defined( WIN32 ) && !defined( _X360 )
  105. if ( g_hMapObject )
  106. {
  107. CloseHandle( g_hMapObject );
  108. g_pMumbleMemory = NULL;
  109. g_hMapObject = NULL;
  110. }
  111. #elif defined( POSIX )
  112. if ( g_pMumbleMemory )
  113. {
  114. munmap( g_pMumbleMemory, sizeof(struct MumbleSharedMemory_t) );
  115. g_pMumbleMemory = NULL;
  116. }
  117. #endif
  118. }
  119. void VectorToMumbleFloatArray( const Vector &vec, float *rgfl )
  120. {
  121. // Traditional left-handed coordinate system
  122. rgfl[0] = vec.x; // X
  123. rgfl[1] = vec.z; // Y is up
  124. rgfl[2] = vec.y; // Z is into the screen
  125. }
  126. void CMumbleSystem::PostRender()
  127. {
  128. #ifndef NO_STEAM
  129. if ( !g_pMumbleMemory || !sv_mumble_positionalaudio.GetBool() )
  130. return;
  131. if ( g_pMumbleMemory->uiVersion != 2 )
  132. {
  133. V_wcscpy_safe( g_pMumbleMemory->name, L"Source: " );
  134. wchar_t wcsGameDir[MAX_PATH];
  135. Q_UTF8ToUnicode( COM_GetModDirectory(), wcsGameDir, sizeof(wcsGameDir) );
  136. V_wcscat_safe( g_pMumbleMemory->name, wcsGameDir );
  137. V_wcscpy_safe( g_pMumbleMemory->description, L"Links Source engine games to Mumble." );
  138. g_pMumbleMemory->uiVersion = 2;
  139. }
  140. g_pMumbleMemory->uiTick++;
  141. Vector vecOriginPlayer, vecOriginCamera = MainViewOrigin( 0 );
  142. QAngle anglesPlayer, anglesCamera = MainViewAngles( 0 );
  143. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  144. if ( pPlayer )
  145. {
  146. bool bIsOnTeam = pPlayer->GetTeamNumber() == TEAM_TERRORIST || pPlayer->GetTeamNumber() == TEAM_CT;
  147. if ( pPlayer->IsAlive() && bIsOnTeam )
  148. {
  149. vecOriginPlayer = pPlayer->EyePosition();
  150. }
  151. else
  152. {
  153. // a zero player origin disables positional audio
  154. vecOriginPlayer = vec3_origin;
  155. }
  156. anglesPlayer = pPlayer->GetAbsAngles();
  157. }
  158. else
  159. {
  160. vecOriginPlayer = vecOriginCamera;
  161. anglesPlayer = anglesCamera;
  162. }
  163. anglesPlayer.x = 0;
  164. Vector vecPlayerForward, vecPlayerUp, vecCameraForward, vecCameraUp;
  165. AngleVectors( anglesPlayer, &vecPlayerForward, NULL, &vecPlayerUp );
  166. AngleVectors( anglesCamera, &vecCameraForward, NULL, &vecCameraUp );
  167. // 1 Source unit is about one inch
  168. // 1 mumble unit = 1 meter
  169. vecOriginPlayer *= METERS_PER_INCH;
  170. vecOriginCamera *= METERS_PER_INCH;
  171. VectorToMumbleFloatArray( vecPlayerForward, g_pMumbleMemory->fAvatarFront );
  172. VectorToMumbleFloatArray( vecPlayerUp, g_pMumbleMemory->fAvatarTop );
  173. VectorToMumbleFloatArray( vecOriginPlayer, g_pMumbleMemory->fAvatarPosition );
  174. VectorToMumbleFloatArray( vecCameraForward, g_pMumbleMemory->fCameraFront );
  175. VectorToMumbleFloatArray( vecCameraUp, g_pMumbleMemory->fCameraTop );
  176. VectorToMumbleFloatArray( vecOriginCamera, g_pMumbleMemory->fCameraPosition );
  177. if ( pPlayer && m_bHasSetPlayerUniqueId && m_nTeamSetInUniqueId != pPlayer->GetTeamNumber() )
  178. {
  179. // Player changed team since we set the unique ID. Set it again.
  180. m_bHasSetPlayerUniqueId = false;
  181. }
  182. if ( !m_bHasSetPlayerUniqueId && steamapicontext && steamapicontext->SteamUser() )
  183. {
  184. CSteamID steamid = steamapicontext->SteamUser()->GetSteamID();
  185. if ( steamid.IsValid() )
  186. {
  187. int unTeam = pPlayer ? pPlayer->GetTeamNumber() : 0;
  188. char szSteamId[256];
  189. V_sprintf_safe( szSteamId, "universe:%u;account_type:%u;id:%u;instance:%u;team:%d", steamid.GetEUniverse(), steamid.GetEAccountType(), steamid.GetAccountID(), steamid.GetUnAccountInstance(), unTeam );
  190. wchar_t wcsSteamId[256];
  191. Q_UTF8ToUnicode( szSteamId, wcsSteamId, sizeof(wcsSteamId) );
  192. // Identifier which uniquely identifies a certain player in a context.
  193. V_wcscpy_safe( g_pMumbleMemory->identity, wcsSteamId );
  194. m_bHasSetPlayerUniqueId = true;
  195. m_nTeamSetInUniqueId = unTeam;
  196. }
  197. }
  198. // Context should be equal for players which should be able to hear each other positional and
  199. // differ for those who shouldn't (e.g. it could contain the server+port and team)
  200. memcpy( g_pMumbleMemory->context, &m_szSteamIDCurrentServer, m_cubSteamIDCurrentServer );
  201. g_pMumbleMemory->context_len = m_cubSteamIDCurrentServer;
  202. #endif // NO_STEAM
  203. }
  204. void CMumbleSystem::FireGameEvent( IGameEvent *event )
  205. {
  206. #ifndef NO_STEAM
  207. const char *eventname = event->GetName();
  208. if ( !eventname || !eventname[0] )
  209. return;
  210. if ( !Q_strcmp( "server_spawn", eventname ) )
  211. {
  212. V_strcpy_safe( m_szSteamIDCurrentServer, event->GetString( "steamid", "" ) );
  213. m_cubSteamIDCurrentServer = strlen( m_szSteamIDCurrentServer ) + 1;
  214. }
  215. #endif // NO_STEAM
  216. }