diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/shared/voice_status.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/shared/voice_status.cpp')
| -rw-r--r-- | mp/src/game/shared/voice_status.cpp | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/mp/src/game/shared/voice_status.cpp b/mp/src/game/shared/voice_status.cpp new file mode 100644 index 00000000..4d295713 --- /dev/null +++ b/mp/src/game/shared/voice_status.cpp @@ -0,0 +1,591 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "basetypes.h"
+#include "hud.h"
+#include <string.h>
+#include <stdio.h>
+#include "voice_status.h"
+#include "r_efx.h"
+#include <vgui_controls/TextImage.h>
+#include <vgui/MouseCode.h>
+#include "cdll_client_int.h"
+#include "hud_macros.h"
+#include "c_playerresource.h"
+#include "cliententitylist.h"
+#include "c_baseplayer.h"
+#include "materialsystem/imesh.h"
+#include "view.h"
+#include "convar.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include "vgui_bitmapimage.h"
+#include "materialsystem/imaterial.h"
+#include "tier0/dbg.h"
+#include "cdll_int.h"
+#include <vgui/IPanel.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+
+extern int cam_thirdperson;
+
+
+#define VOICE_MODEL_INTERVAL 0.3
+#define SQUELCHOSCILLATE_PER_SECOND 2.0f
+
+ConVar voice_modenable( "voice_modenable", "1", FCVAR_ARCHIVE | FCVAR_CLIENTCMD_CAN_EXECUTE, "Enable/disable voice in this mod." );
+ConVar voice_clientdebug( "voice_clientdebug", "0" );
+
+// ---------------------------------------------------------------------- //
+// The voice manager for the client.
+// ---------------------------------------------------------------------- //
+static CVoiceStatus *g_VoiceStatus = NULL;
+
+CVoiceStatus* GetClientVoiceMgr()
+{
+ if ( !g_VoiceStatus )
+ {
+ ClientVoiceMgr_Init();
+ }
+
+ return g_VoiceStatus;
+}
+
+void ClientVoiceMgr_Init()
+{
+ if ( g_VoiceStatus )
+ return;
+
+ g_VoiceStatus = new CVoiceStatus();
+}
+
+void ClientVoiceMgr_Shutdown()
+{
+ delete g_VoiceStatus;
+ g_VoiceStatus = NULL;
+}
+
+// ---------------------------------------------------------------------- //
+// CVoiceStatus.
+// ---------------------------------------------------------------------- //
+
+static CVoiceStatus *g_pInternalVoiceStatus = NULL;
+
+void __MsgFunc_VoiceMask(bf_read &msg)
+{
+ if(g_pInternalVoiceStatus)
+ g_pInternalVoiceStatus->HandleVoiceMaskMsg(msg);
+}
+
+void __MsgFunc_RequestState(bf_read &msg)
+{
+ if(g_pInternalVoiceStatus)
+ g_pInternalVoiceStatus->HandleReqStateMsg(msg);
+}
+
+
+// ---------------------------------------------------------------------- //
+// CVoiceStatus.
+// ---------------------------------------------------------------------- //
+
+CVoiceStatus::CVoiceStatus()
+{
+ m_nControlSize = 0;
+ m_bBanMgrInitialized = false;
+ m_LastUpdateServerState = 0;
+
+ m_bTalking = m_bServerAcked = false;
+
+#ifdef VOICE_VOX_ENABLE
+ m_bAboveThresholdTimer.Invalidate();
+#endif // VOICE_VOX_ENABLE
+
+ m_bServerModEnable = -1;
+
+ m_pHeadLabelMaterial = NULL;
+
+ m_bHeadLabelsDisabled = false;
+}
+
+
+CVoiceStatus::~CVoiceStatus()
+{
+ if ( m_pHeadLabelMaterial )
+ {
+ m_pHeadLabelMaterial->DecrementReferenceCount();
+ }
+
+ g_pInternalVoiceStatus = NULL;
+
+ const char *pGameDir = engine->GetGameDirectory();
+ if( pGameDir )
+ {
+ if(m_bBanMgrInitialized)
+ {
+ m_BanMgr.SaveState( pGameDir );
+ }
+ }
+}
+
+int CVoiceStatus::Init(
+ IVoiceStatusHelper *pHelper,
+ VPANEL pParentPanel)
+{
+ const char *pGameDir = engine->GetGameDirectory();
+ if( pGameDir )
+ {
+ m_BanMgr.Init( pGameDir );
+ m_bBanMgrInitialized = true;
+ }
+
+ Assert(!g_pInternalVoiceStatus);
+ g_pInternalVoiceStatus = this;
+
+
+ m_pHeadLabelMaterial = materials->FindMaterial( "voice/icntlk_pl", TEXTURE_GROUP_VGUI );
+ m_pHeadLabelMaterial->IncrementReferenceCount();
+
+ m_bInSquelchMode = false;
+
+ m_pHelper = pHelper;
+ m_pParentPanel = pParentPanel;
+
+ HOOK_MESSAGE(VoiceMask);
+ HOOK_MESSAGE(RequestState);
+
+ return 1;
+}
+
+
+BitmapImage* vgui_LoadMaterial( vgui::VPANEL pParent, const char *pFilename )
+{
+ return new BitmapImage( pParent, pFilename );
+}
+
+
+void CVoiceStatus::VidInit()
+{
+}
+
+
+void CVoiceStatus::Frame(double frametime)
+{
+ // check server banned players once per second
+ if (gpGlobals->curtime - m_LastUpdateServerState > 1)
+ {
+ UpdateServerState(false);
+ }
+}
+
+
+float g_flHeadOffset = 35;
+float g_flHeadIconSize = 8;
+
+
+void CVoiceStatus::SetHeadLabelOffset( float offset )
+{
+ g_flHeadOffset = offset;
+}
+
+float CVoiceStatus::GetHeadLabelOffset( void ) const
+{
+ return g_flHeadOffset;
+}
+
+
+void CVoiceStatus::DrawHeadLabels()
+{
+ if ( m_bHeadLabelsDisabled )
+ return;
+
+ if ( GameRules() && ( GameRules()->ShouldDrawHeadLabels() == false ) )
+ return;
+
+ if( !m_pHeadLabelMaterial )
+ return;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ for(int i=0; i < VOICE_MAX_PLAYERS; i++)
+ {
+ if ( !m_VoicePlayers[i] )
+ continue;
+
+ IClientNetworkable *pClient = cl_entitylist->GetClientEntity( i+1 );
+
+ // Don't show an icon if the player is not in our PVS.
+ if ( !pClient || pClient->IsDormant() )
+ continue;
+
+ C_BasePlayer *pPlayer = dynamic_cast<C_BasePlayer*>(pClient);
+ if( !pPlayer )
+ continue;
+
+ // Don't show an icon for dead or spectating players (ie: invisible entities).
+ if( pPlayer->IsPlayerDead() )
+ continue;
+
+ // Place it 20 units above his head.
+ Vector vOrigin = pPlayer->WorldSpaceCenter();
+ vOrigin.z += g_flHeadOffset;
+
+
+ // Align it so it never points up or down.
+ Vector vUp( 0, 0, 1 );
+ Vector vRight = CurrentViewRight();
+ if ( fabs( vRight.z ) > 0.95 ) // don't draw it edge-on
+ continue;
+
+ vRight.z = 0;
+ VectorNormalize( vRight );
+
+
+ float flSize = g_flHeadIconSize;
+
+ pRenderContext->Bind( pPlayer->GetHeadLabelMaterial() );
+ IMesh *pMesh = pRenderContext->GetDynamicMesh();
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,0,0 );
+ meshBuilder.Position3fv( (vOrigin + (vRight * -flSize) + (vUp * flSize)).Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,1,0 );
+ meshBuilder.Position3fv( (vOrigin + (vRight * flSize) + (vUp * flSize)).Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,1,1 );
+ meshBuilder.Position3fv( (vOrigin + (vRight * flSize) + (vUp * -flSize)).Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color3f( 1.0, 1.0, 1.0 );
+ meshBuilder.TexCoord2f( 0,0,1 );
+ meshBuilder.Position3fv( (vOrigin + (vRight * -flSize) + (vUp * -flSize)).Base() );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.End();
+ pMesh->Draw();
+ }
+}
+
+
+void CVoiceStatus::UpdateSpeakerStatus(int entindex, bool bTalking)
+{
+ if(!m_pParentPanel)
+ return;
+
+ if( voice_clientdebug.GetInt() )
+ {
+ Msg( "CVoiceStatus::UpdateSpeakerStatus: ent %d talking = %d\n", entindex, bTalking );
+ }
+
+ // Is it the local player talking?
+ if( entindex == -1 )
+ {
+ m_bTalking = !!bTalking;
+ if( bTalking )
+ {
+ // Enable voice for them automatically if they try to talk.
+ engine->ClientCmd( "voice_modenable 1" );
+ }
+ }
+ else if( entindex == -2 )
+ {
+ m_bServerAcked = !!bTalking;
+ }
+#ifdef VOICE_VOX_ENABLE
+ else if( entindex == -3 )
+ {
+ if ( bTalking )
+ {
+ const float AboveThresholdMinDuration = 0.5f;
+ m_bAboveThresholdTimer.Start( AboveThresholdMinDuration );
+ }
+ }
+#endif // VOICE_VOX_ENABLE
+ else if(entindex > 0 && entindex <= VOICE_MAX_PLAYERS)
+ {
+ int iClient = entindex - 1;
+ if(iClient < 0)
+ return;
+
+ if(bTalking)
+ {
+ m_VoicePlayers[iClient] = true;
+ m_VoiceEnabledPlayers[iClient] = true;
+ }
+ else
+ {
+ m_VoicePlayers[iClient] = false;
+ }
+ }
+}
+
+
+void CVoiceStatus::UpdateServerState(bool bForce)
+{
+ // Can't do anything when we're not in a level.
+ if( !g_bLevelInitialized )
+ {
+ if( voice_clientdebug.GetInt() )
+ {
+ Msg( "CVoiceStatus::UpdateServerState: g_bLevelInitialized\n" );
+ }
+
+ return;
+ }
+
+ int bCVarModEnable = !!voice_modenable.GetInt();
+ if(bForce || m_bServerModEnable != bCVarModEnable)
+ {
+ m_bServerModEnable = bCVarModEnable;
+
+ char str[256];
+ Q_snprintf(str, sizeof(str), "VModEnable %d", m_bServerModEnable);
+ engine->ServerCmd(str);
+
+ if( voice_clientdebug.GetInt() )
+ {
+ Msg( "CVoiceStatus::UpdateServerState: Sending '%s'\n", str );
+ }
+ }
+
+ char str[2048];
+ Q_strncpy(str,"vban",sizeof(str));
+ bool bChange = false;
+
+ for(unsigned long dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++)
+ {
+ unsigned long serverBanMask = 0;
+ unsigned long banMask = 0;
+ for(unsigned long i=0; i < 32; i++)
+ {
+ int playerIndex = ( dw * 32 + i );
+ if ( playerIndex >= MAX_PLAYERS )
+ break;
+
+ player_info_t pi;
+
+ if ( !engine->GetPlayerInfo( i+1, &pi ) )
+ continue;
+
+ if ( m_BanMgr.GetPlayerBan( pi.guid ) )
+ {
+ banMask |= 1 << i;
+ }
+
+ if ( m_ServerBannedPlayers[playerIndex] )
+ {
+ serverBanMask |= 1 << i;
+ }
+ }
+
+ if ( serverBanMask != banMask )
+ {
+ bChange = true;
+ }
+
+ // Ok, the server needs to be updated.
+ char numStr[512];
+ Q_snprintf(numStr, sizeof(numStr), " %lx", banMask);
+ Q_strncat(str, numStr, sizeof(str), COPY_ALL_CHARACTERS);
+ }
+
+ if(bChange || bForce)
+ {
+ if( voice_clientdebug.GetInt() )
+ {
+ Msg( "CVoiceStatus::UpdateServerState: Sending '%s'\n", str );
+ }
+
+ engine->ServerCmd( str, false ); // Tell the server..
+ }
+ else
+ {
+ if( voice_clientdebug.GetInt() )
+ {
+ Msg( "CVoiceStatus::UpdateServerState: no change\n" );
+ }
+ }
+
+ m_LastUpdateServerState = gpGlobals->curtime;
+}
+
+void CVoiceStatus::HandleVoiceMaskMsg(bf_read &msg)
+{
+ unsigned long dw;
+ for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++)
+ {
+ m_AudiblePlayers.SetDWord(dw, (unsigned long)msg.ReadLong());
+ m_ServerBannedPlayers.SetDWord(dw, (unsigned long)msg.ReadLong());
+
+ if( voice_clientdebug.GetInt())
+ {
+ Msg("CVoiceStatus::HandleVoiceMaskMsg\n");
+ Msg(" - m_AudiblePlayers[%d] = %lu\n", dw, m_AudiblePlayers.GetDWord(dw));
+ Msg(" - m_ServerBannedPlayers[%d] = %lu\n", dw, m_ServerBannedPlayers.GetDWord(dw));
+ }
+ }
+
+ m_bServerModEnable = msg.ReadByte();
+}
+
+void CVoiceStatus::HandleReqStateMsg(bf_read &msg)
+{
+ if(voice_clientdebug.GetInt())
+ {
+ Msg("CVoiceStatus::HandleReqStateMsg\n");
+ }
+
+ UpdateServerState(true);
+}
+
+void CVoiceStatus::StartSquelchMode()
+{
+ if(m_bInSquelchMode)
+ return;
+
+ m_bInSquelchMode = true;
+ m_pHelper->UpdateCursorState();
+}
+
+void CVoiceStatus::StopSquelchMode()
+{
+ m_bInSquelchMode = false;
+ m_pHelper->UpdateCursorState();
+}
+
+bool CVoiceStatus::IsInSquelchMode()
+{
+ return m_bInSquelchMode;
+}
+
+void SetOrUpdateBounds(
+ vgui::Panel *pPanel,
+ int left, int top, int wide, int tall,
+ bool bOnlyUpdateBounds, int &topCoord, int &bottomCoord )
+{
+ if ( bOnlyUpdateBounds )
+ {
+ if ( top < topCoord )
+ topCoord = top;
+
+ if ( (top+tall) >= bottomCoord )
+ bottomCoord = top+tall;
+ }
+ else
+ {
+ pPanel->SetBounds( left, top, wide, tall );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the target client has been banned
+// Input : playerID -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CVoiceStatus::IsPlayerBlocked(int iPlayer)
+{
+ player_info_t pi;
+
+ if ( !engine->GetPlayerInfo( iPlayer, &pi ) )
+ return false;
+
+ return m_BanMgr.GetPlayerBan( pi.guid );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the player can't hear the other client due to game rules (eg. the other team)
+// Input : playerID -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CVoiceStatus::IsPlayerAudible(int iPlayer)
+{
+ return !!m_AudiblePlayers[iPlayer-1];
+}
+
+
+//-----------------------------------------------------------------------------
+// returns true if the player is currently speaking
+//-----------------------------------------------------------------------------
+bool CVoiceStatus::IsPlayerSpeaking(int iPlayerIndex)
+{
+ return m_VoicePlayers[iPlayerIndex-1] != 0;
+}
+
+//-----------------------------------------------------------------------------
+// returns true if the local player is attempting to speak
+//-----------------------------------------------------------------------------
+bool CVoiceStatus::IsLocalPlayerSpeaking( void )
+{
+#ifdef VOICE_VOX_ENABLE
+ if ( voice_vox.GetBool() )
+ {
+ if ( m_bAboveThresholdTimer.IsElapsed() == true )
+ {
+ return false;
+ }
+ }
+#endif // VOICE_VOX_ENABLE
+
+ return m_bTalking;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: blocks/unblocks the target client from being heard
+// Input : playerID -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+void CVoiceStatus::SetPlayerBlockedState(int iPlayer, bool blocked)
+{
+ if (voice_clientdebug.GetInt())
+ {
+ Msg( "CVoiceStatus::SetPlayerBlockedState part 1\n" );
+ }
+
+ player_info_t pi;
+ if ( !engine->GetPlayerInfo( iPlayer, &pi ) )
+ return;
+
+ if (voice_clientdebug.GetInt())
+ {
+ Msg( "CVoiceStatus::SetPlayerBlockedState part 2\n" );
+ }
+
+ // Squelch or (try to) unsquelch this player.
+ if (voice_clientdebug.GetInt())
+ {
+ Msg("CVoiceStatus::SetPlayerBlockedState: setting player %d ban to %d\n", iPlayer, !m_BanMgr.GetPlayerBan(pi.guid));
+ }
+
+ m_BanMgr.SetPlayerBan(pi.guid, !m_BanMgr.GetPlayerBan(pi.guid));
+ UpdateServerState(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVoiceStatus::SetHeadLabelMaterial( const char *pszMaterial )
+{
+ if ( m_pHeadLabelMaterial )
+ {
+ m_pHeadLabelMaterial->DecrementReferenceCount();
+ m_pHeadLabelMaterial = NULL;
+ }
+
+ m_pHeadLabelMaterial = materials->FindMaterial( pszMaterial, TEXTURE_GROUP_VGUI );
+ m_pHeadLabelMaterial->IncrementReferenceCount();
+}
\ No newline at end of file |