813 lines
19 KiB
C++
813 lines
19 KiB
C++
//========= Copyright © 1996-2005, 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>
|
|
#include "con_nprint.h"
|
|
|
|
#if defined(PORTAL2)
|
|
#include "c_portal_gamestats.h"
|
|
#endif
|
|
|
|
#if defined ( CSTRIKE15 )
|
|
#include "c_cs_player.h"
|
|
#include "matchmaking/imatchtitle.h"
|
|
#include "matchmaking/iplayer.h"
|
|
#include "matchmaking/mm_helpers.h"
|
|
#include "matchmaking/imatchframework.h"
|
|
#endif
|
|
|
|
// 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" );
|
|
ConVar voice_head_icon_size( "voice_head_icon_size", "6", FCVAR_NONE, "Size of voice icon over player heads in inches" );
|
|
ConVar voice_head_icon_height( "voice_head_icon_height", "20", FCVAR_NONE, "Voice icons are this many inches over player eye positions" );
|
|
ConVar voice_local_icon( "voice_local_icon", "0", FCVAR_NONE, "Draw local player's voice icon" );
|
|
ConVar voice_all_icons( "voice_all_icons", "0", FCVAR_NONE, "Draw all players' voice icons" );
|
|
ConVar voice_icons_method( "voice_icons_method", "2", FCVAR_NONE, "0 = classic style, 1 = particles, 2 = integrated into target ID" );
|
|
|
|
#if defined ( CSTRIKE15 )
|
|
ConVar cl_mute_enemy_team( "cl_mute_enemy_team", "0", FCVAR_ARCHIVE, "Block all communication from players on the enemy team." );
|
|
ConVar cl_mute_all_but_friends_and_party( "cl_mute_all_but_friends_and_party", "0", FCVAR_ARCHIVE, "Only allow communication from friends and matchmaking party members. Doesn't apply to competitive matchmaking games." );
|
|
#endif
|
|
|
|
// ---------------------------------------------------------------------- //
|
|
// 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;
|
|
}
|
|
|
|
void ClientVoiceMgr_LevelInit()
|
|
{
|
|
if ( g_VoiceStatus )
|
|
{
|
|
g_VoiceStatus->LevelInit();
|
|
}
|
|
}
|
|
|
|
void ClientVoiceMgr_LevelShutdown()
|
|
{
|
|
if ( g_VoiceStatus )
|
|
{
|
|
g_VoiceStatus->LevelShutdown();
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------- //
|
|
// CVoiceStatus.
|
|
// ---------------------------------------------------------------------- //
|
|
|
|
static CVoiceStatus *g_pInternalVoiceStatus = NULL;
|
|
|
|
bool __MsgFunc_VoiceMask(const CCSUsrMsg_VoiceMask &msg)
|
|
{
|
|
if(g_pInternalVoiceStatus)
|
|
return g_pInternalVoiceStatus->HandleVoiceMaskMsg(msg);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool __MsgFunc_RequestState(const CCSUsrMsg_RequestState &msg)
|
|
{
|
|
if(g_pInternalVoiceStatus)
|
|
return g_pInternalVoiceStatus->HandleReqStateMsg(msg);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------- //
|
|
// CVoiceStatus.
|
|
// ---------------------------------------------------------------------- //
|
|
|
|
CVoiceStatus::CVoiceStatus()
|
|
{
|
|
m_nControlSize = 0;
|
|
m_bBanMgrInitialized = false;
|
|
m_LastUpdateServerState = 0;
|
|
|
|
for ( int k = 0; k < MAX_SPLITSCREEN_CLIENTS; ++ k )
|
|
{
|
|
m_bTalking[k] = false;
|
|
m_bServerAcked[k] = false;
|
|
m_bAboveThreshold[k] = false;
|
|
|
|
m_bAboveThresholdTimer[k].Invalidate();
|
|
}
|
|
|
|
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;
|
|
|
|
for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh )
|
|
{
|
|
ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
|
|
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::LevelInit( void )
|
|
{
|
|
for ( int k = 0; k < MAX_SPLITSCREEN_CLIENTS; ++ k )
|
|
{
|
|
m_bTalking[k] = false;
|
|
m_bAboveThreshold[k] = false;
|
|
m_bAboveThresholdTimer[k].Invalidate();
|
|
}
|
|
|
|
for ( int k = 0; k < VOICE_MAX_PLAYERS; ++k )
|
|
{
|
|
m_flTalkTime[k] = 0.0f;
|
|
m_flTimeLastUpdate[k] = 0.0f;
|
|
}
|
|
}
|
|
|
|
|
|
void CVoiceStatus::LevelShutdown( void )
|
|
{
|
|
for ( int k = 0; k < MAX_SPLITSCREEN_CLIENTS; ++ k )
|
|
{
|
|
m_bTalking[k] = false;
|
|
m_bAboveThreshold[k] = false;
|
|
m_bAboveThresholdTimer[k].Invalidate();
|
|
}
|
|
|
|
for ( int k = 0; k < VOICE_MAX_PLAYERS; ++k )
|
|
{
|
|
m_flTalkTime[k] = 0.0f;
|
|
m_flTimeLastUpdate[k] = 0.0f;
|
|
}
|
|
}
|
|
|
|
|
|
void CVoiceStatus::Frame(double frametime)
|
|
{
|
|
// check server banned players once per second
|
|
if (gpGlobals->curtime - m_LastUpdateServerState > 1)
|
|
{
|
|
UpdateServerState(false);
|
|
}
|
|
}
|
|
|
|
float CVoiceStatus::GetHeadLabelOffset( void ) const
|
|
{
|
|
return voice_head_icon_height.GetFloat();
|
|
}
|
|
|
|
|
|
void CVoiceStatus::DrawHeadLabels()
|
|
{
|
|
if ( voice_all_icons.GetBool() )
|
|
{
|
|
for(int i=0; i < VOICE_MAX_PLAYERS; i++)
|
|
{
|
|
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;
|
|
|
|
m_VoicePlayers[i] = voice_all_icons.GetInt() > 0;
|
|
}
|
|
}
|
|
else if ( voice_local_icon.GetBool() )
|
|
{
|
|
C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
|
|
m_VoicePlayers[ localPlayer->entindex() - 1 ] = IsLocalPlayerSpeakingAboveThreshold( localPlayer->GetSplitScreenPlayerSlot() );
|
|
}
|
|
|
|
if ( m_bHeadLabelsDisabled )
|
|
return;
|
|
|
|
if( !m_pHeadLabelMaterial )
|
|
return;
|
|
|
|
CMatRenderContextPtr pRenderContext( materials );
|
|
|
|
for ( int i=0; i < VOICE_MAX_PLAYERS; i++)
|
|
{
|
|
IClientNetworkable *pClient = cl_entitylist->GetClientEntity( i+1 );
|
|
|
|
C_BasePlayer *pPlayer = dynamic_cast< C_BasePlayer* >( pClient );
|
|
if( !pPlayer )
|
|
continue;
|
|
|
|
if ( !m_VoicePlayers[i] )
|
|
{
|
|
if ( voice_icons_method.GetInt() > 0 )
|
|
{
|
|
pPlayer->UpdateSpeechVOIP( false );
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Don't show an icon if the player is not in our PVS.
|
|
if ( !pClient || pClient->IsDormant() )
|
|
{
|
|
if ( voice_icons_method.GetInt() > 0 )
|
|
{
|
|
pPlayer->UpdateSpeechVOIP( false );
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Don't show an icon for dead or spectating players (ie: invisible entities).
|
|
if( pPlayer->IsPlayerDead() )
|
|
{
|
|
if ( voice_icons_method.GetInt() > 0 )
|
|
{
|
|
pPlayer->UpdateSpeechVOIP( false );
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( voice_icons_method.GetInt() > 0 )
|
|
{
|
|
pPlayer->UpdateSpeechVOIP( true );
|
|
return;
|
|
}
|
|
|
|
// Don't show an icon for players we can't hear
|
|
if ( !IsPlayerAudible( i+1 ) )
|
|
continue;
|
|
|
|
// Place it a fixed height above his head.
|
|
Vector vOrigin = pPlayer->EyePosition( );
|
|
vOrigin.z += GetHeadLabelOffset();
|
|
|
|
// 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 = voice_head_icon_size.GetFloat();
|
|
|
|
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, int iSsSlot, bool bTalking)
|
|
{
|
|
if( !m_pParentPanel )
|
|
return;
|
|
|
|
if( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
Msg( "CVoiceStatus::UpdateSpeakerStatus: ent %d ss[%d] talking = %d\n",
|
|
entindex, iSsSlot, bTalking );
|
|
}
|
|
else if ( voice_clientdebug.GetInt() == 2 )
|
|
{
|
|
con_nprint_t np;
|
|
np.index = 0;
|
|
np.color[0] = 1.0f;
|
|
np.color[1] = 1.0f;
|
|
np.color[2] = 1.0f;
|
|
np.time_to_live = 2.0f;
|
|
np.fixed_width_font = true;
|
|
|
|
int numActiveChannels = VOICE_MAX_PLAYERS;
|
|
engine->Con_NXPrintf ( &np, "Total Players: %i", numActiveChannels);
|
|
|
|
for ( int i = 1; i <= numActiveChannels; i++ )
|
|
{
|
|
np.index++;
|
|
np.color[0] = np.color[1] = np.color[2] = ( i % 2 == 0 ? 0.9f : 0.7f );
|
|
|
|
if ( !IsPlayerBlocked( i ) && IsPlayerAudible( i ) && !ShouldHideCommunicationFromPlayer( i ) && IsPlayerSpeaking( i ) )
|
|
{
|
|
np.color[0] = 0.0f;
|
|
np.color[1] = 1.0f;
|
|
np.color[2] = 0.0f;
|
|
}
|
|
|
|
engine->Con_NXPrintf ( &np, "%02i enabled(%s) blocked(%s) audible(%s) speaking(%s)",
|
|
i,
|
|
m_VoiceEnabledPlayers[ i - 1 ] != 0 ? "YES" : " NO",
|
|
IsPlayerBlocked( i ) ? "YES" : " NO",
|
|
IsPlayerAudible( i ) ? "YES" : " NO",
|
|
IsPlayerSpeaking( i ) ? "YES" : " NO" );
|
|
}
|
|
|
|
np.color[0] = 1.0f;
|
|
np.color[1] = 1.0f;
|
|
np.color[2] = 1.0f;
|
|
|
|
np.index += 2;
|
|
numActiveChannels = MAX_SPLITSCREEN_CLIENTS;
|
|
engine->Con_NXPrintf ( &np, "Local Players: %i", numActiveChannels);
|
|
|
|
for ( int i = 0; i < numActiveChannels; i++ )
|
|
{
|
|
np.index++;
|
|
np.color[0] = np.color[1] = np.color[2] = ( i % 2 == 0 ? 0.9f : 0.7f );
|
|
|
|
if ( IsLocalPlayerSpeaking( i ) && IsLocalPlayerSpeakingAboveThreshold( i ) )
|
|
{
|
|
np.color[0] = 0.0f;
|
|
np.color[1] = 1.0f;
|
|
np.color[2] = 0.0f;
|
|
}
|
|
|
|
engine->Con_NXPrintf ( &np, "%02i speaking(%s) above_threshold(%s)",
|
|
i,
|
|
IsLocalPlayerSpeaking( i ) ? "YES" : " NO",
|
|
IsLocalPlayerSpeakingAboveThreshold( i ) ? "YES" : " NO" );
|
|
}
|
|
}
|
|
|
|
// Is it the local player talking?
|
|
if( entindex == -1 && iSsSlot >= 0 )
|
|
{
|
|
m_bTalking[ iSsSlot ] = !!bTalking;
|
|
#if !defined( CSTRIKE15 )
|
|
if( bTalking )
|
|
{
|
|
// Enable voice for them automatically if they try to talk.
|
|
char chClientCmd[0xFF];
|
|
Q_snprintf( chClientCmd, sizeof( chClientCmd ),
|
|
"cmd%d voice_modenable 1", iSsSlot + 1 );
|
|
engine->ClientCmd( chClientCmd );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if( entindex == -2 && iSsSlot >= 0 )
|
|
{
|
|
m_bServerAcked[ iSsSlot ] = !!bTalking;
|
|
}
|
|
|
|
if ( entindex == -3 && iSsSlot >= 0 )
|
|
{
|
|
m_bAboveThreshold[ iSsSlot ] = !!bTalking;
|
|
|
|
if ( bTalking )
|
|
{
|
|
const float AboveThresholdMinDuration = 0.5f;
|
|
m_bAboveThresholdTimer[ iSsSlot ].Start( AboveThresholdMinDuration );
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if ( bTalking && m_bAboveThresholdTimer[ iClient ].IsElapsed() )
|
|
{
|
|
m_flTalkTime[ iClient ] += (gpGlobals->curtime - m_flTimeLastUpdate[ iClient ]);
|
|
}
|
|
else
|
|
{
|
|
#if defined( PORTAL2 ) && !defined( _GAMECONSOLE )
|
|
if ( m_flTalkTime[ iClient ] > 0.0f )
|
|
{
|
|
g_PortalGameStats.Event_MicUsage( entindex, m_flTalkTime[ iClient ], gpGlobals->curtime - m_flTalkTime[ iClient ] );
|
|
}
|
|
#endif //!defined( _GAMECONSOLE )
|
|
m_flTalkTime[ iClient ] = 0.0f;
|
|
}
|
|
m_flTimeLastUpdate[ iClient ] = gpGlobals->curtime;
|
|
}
|
|
}
|
|
|
|
|
|
void CVoiceStatus::UpdateServerState(bool bForce)
|
|
{
|
|
// Can't do anything when we're not in a level.
|
|
if( !g_bLevelInitialized )
|
|
{
|
|
if( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
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);
|
|
|
|
{
|
|
HACK_GETLOCALPLAYER_GUARD( "CVoiceStatus::UpdateServerState" );
|
|
engine->ServerCmd(str);
|
|
}
|
|
|
|
if( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
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 ) || ShouldHideCommunicationFromPlayer( i + 1 ) )
|
|
{
|
|
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() == 1 )
|
|
{
|
|
Msg( "CVoiceStatus::UpdateServerState: Sending '%s'\n", str );
|
|
}
|
|
|
|
engine->ServerCmd( str, false ); // Tell the server..
|
|
}
|
|
else
|
|
{
|
|
if( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
Msg( "CVoiceStatus::UpdateServerState: no change\n" );
|
|
}
|
|
}
|
|
|
|
m_LastUpdateServerState = gpGlobals->curtime;
|
|
}
|
|
|
|
bool CVoiceStatus::HandleVoiceMaskMsg(const CCSUsrMsg_VoiceMask &msg)
|
|
{
|
|
unsigned long dw;
|
|
for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++)
|
|
{
|
|
m_AudiblePlayers.SetDWord(dw, (unsigned long)msg.player_masks(dw).game_rules_mask());
|
|
m_ServerBannedPlayers.SetDWord(dw, (unsigned long)msg.player_masks(dw).ban_masks());
|
|
|
|
if( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
Msg("CVoiceStatus::HandleVoiceMaskMsg\n");
|
|
Msg(" - m_AudiblePlayers[%lu] = %u\n", dw, m_AudiblePlayers.GetDWord(dw));
|
|
Msg(" - m_ServerBannedPlayers[%lu] = %u\n", dw, m_ServerBannedPlayers.GetDWord(dw));
|
|
}
|
|
}
|
|
|
|
m_bServerModEnable = msg.player_mod_enable();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CVoiceStatus::HandleReqStateMsg(const CCSUsrMsg_RequestState &msg)
|
|
{
|
|
if( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
Msg("CVoiceStatus::HandleReqStateMsg\n");
|
|
}
|
|
|
|
UpdateServerState(true);
|
|
|
|
return 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 );
|
|
}
|
|
|
|
|
|
bool IsPartyMember( XUID xuidPlayer )
|
|
{
|
|
if ( IMatchSession *pMatchSession = g_pMatchFramework->GetMatchSession() )
|
|
{
|
|
return SessionMembersFindPlayer( pMatchSession->GetSessionSettings(), xuidPlayer ) != NULL;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool CVoiceStatus::ShouldHideCommunicationFromPlayer( int iPlayerIndex )
|
|
{
|
|
#if defined ( CSTRIKE15 )
|
|
C_CSPlayer* pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
|
|
if ( pLocalPlayer && pLocalPlayer->entindex() == iPlayerIndex )
|
|
return false;
|
|
|
|
if ( cl_mute_enemy_team.GetBool() )
|
|
{
|
|
if ( pLocalPlayer && pLocalPlayer->IsOtherEnemy( iPlayerIndex ) &&
|
|
( pLocalPlayer->GetTeamNumber() == TEAM_CT || pLocalPlayer->GetTeamNumber() == TEAM_TERRORIST ) )
|
|
return true;
|
|
}
|
|
if ( cl_mute_all_but_friends_and_party.GetBool() && CSGameRules() && !CSGameRules()->IsQueuedMatchmaking() )
|
|
{
|
|
// This type of muting doesn't make sense when playing back a demo
|
|
if ( engine->IsPlayingDemo() )
|
|
return false;
|
|
C_CSPlayer * pOther = ToCSPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
|
|
CSteamID otherID;
|
|
bool bIsInParty = false;
|
|
if ( pOther && pOther->GetSteamID( &otherID ) )
|
|
{
|
|
if ( IsPartyMember( otherID.ConvertToUint64() ) )
|
|
bIsInParty = true;
|
|
}
|
|
|
|
if ( pLocalPlayer && !pLocalPlayer->HasPlayerAsFriend( pOther ) && !bIsInParty )
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: blocks/unblocks the target client from being heard
|
|
// Input : playerID -
|
|
// Output : Returns true on success, false on failure.
|
|
//-----------------------------------------------------------------------------
|
|
void CVoiceStatus::SetPlayerBlockedState( int iPlayer )
|
|
{
|
|
if ( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
Msg( "CVoiceStatus::SetPlayerBlockedState part 1\n" );
|
|
}
|
|
|
|
player_info_t pi;
|
|
if ( !engine->GetPlayerInfo( iPlayer, &pi ) )
|
|
return;
|
|
|
|
if ( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
Msg( "CVoiceStatus::SetPlayerBlockedState part 2\n" );
|
|
}
|
|
|
|
// Squelch or (try to) unsquelch this player.
|
|
if ( voice_clientdebug.GetInt() == 1 )
|
|
{
|
|
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();
|
|
}
|