source-engine/game/server/vguiscreen.cpp

420 lines
12 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: This is an entity that represents a vgui screen
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "vguiscreen.h"
#include "networkstringtable_gamedll.h"
#include "saverestore_stringtable.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// This is an entity that represents a vgui screen
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST(CVGuiScreen, DT_VGuiScreen)
SendPropFloat(SENDINFO(m_flWidth), 0, SPROP_NOSCALE ),
SendPropFloat(SENDINFO(m_flHeight), 0, SPROP_NOSCALE ),
SendPropInt(SENDINFO(m_nAttachmentIndex), 5, SPROP_UNSIGNED ),
SendPropInt(SENDINFO(m_nPanelName), MAX_VGUI_SCREEN_STRING_BITS, SPROP_UNSIGNED ),
SendPropInt(SENDINFO(m_fScreenFlags), VGUI_SCREEN_MAX_BITS, SPROP_UNSIGNED ),
SendPropInt(SENDINFO(m_nOverlayMaterial), MAX_MATERIAL_STRING_BITS, SPROP_UNSIGNED ),
SendPropEHandle(SENDINFO(m_hPlayerOwner)),
END_SEND_TABLE();
LINK_ENTITY_TO_CLASS( vgui_screen, CVGuiScreen );
LINK_ENTITY_TO_CLASS( vgui_screen_team, CVGuiScreen );
PRECACHE_REGISTER( vgui_screen );
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CVGuiScreen )
DEFINE_CUSTOM_FIELD( m_nPanelName, &g_VguiScreenStringOps ),
DEFINE_FIELD( m_nAttachmentIndex, FIELD_INTEGER ),
// DEFINE_FIELD( m_nOverlayMaterial, FIELD_INTEGER ),
DEFINE_FIELD( m_fScreenFlags, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_flWidth, FIELD_FLOAT, "width" ),
DEFINE_KEYFIELD( m_flHeight, FIELD_FLOAT, "height" ),
DEFINE_KEYFIELD( m_strOverlayMaterial, FIELD_STRING, "overlaymaterial" ),
DEFINE_FIELD( m_hPlayerOwner, FIELD_EHANDLE ),
DEFINE_INPUTFUNC( FIELD_VOID, "SetActive", InputSetActive ),
DEFINE_INPUTFUNC( FIELD_VOID, "SetInactive", InputSetInactive ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CVGuiScreen::CVGuiScreen()
{
m_nOverlayMaterial = OVERLAY_MATERIAL_INVALID_STRING;
m_hPlayerOwner = NULL;
}
//-----------------------------------------------------------------------------
// Read in worldcraft data...
//-----------------------------------------------------------------------------
bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue )
{
//!! temp hack, until worldcraft is fixed
// strip the # tokens from (duplicate) key names
char *s = (char *)strchr( szKeyName, '#' );
if ( s )
{
*s = '\0';
}
if ( FStrEq( szKeyName, "panelname" ))
{
SetPanelName( szValue );
return true;
}
// NOTE: Have to do these separate because they set two values instead of one
if( FStrEq( szKeyName, "angles" ) )
{
Assert( GetMoveParent() == NULL );
QAngle angles;
UTIL_StringToVector( angles.Base(), szValue );
// Because the vgui screen basis is strange (z is front, y is up, x is right)
// we need to rotate the typical basis before applying it
VMatrix mat, rotation, tmp;
MatrixFromAngles( angles, mat );
MatrixBuildRotationAboutAxis( rotation, Vector( 0, 1, 0 ), 90 );
MatrixMultiply( mat, rotation, tmp );
MatrixBuildRotateZ( rotation, 90 );
MatrixMultiply( tmp, rotation, mat );
MatrixToAngles( mat, angles );
SetAbsAngles( angles );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//-----------------------------------------------------------------------------
// Precache...
//-----------------------------------------------------------------------------
void CVGuiScreen::Precache()
{
BaseClass::Precache();
if ( m_strOverlayMaterial != NULL_STRING )
{
PrecacheMaterial( STRING(m_strOverlayMaterial) );
}
}
//-----------------------------------------------------------------------------
// Spawn...
//-----------------------------------------------------------------------------
void CVGuiScreen::Spawn()
{
Precache();
// This has no model, but we want it to transmit if it's in the PVS anyways
AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
m_nAttachmentIndex = 0;
SetSolid( SOLID_OBB );
AddSolidFlags( FSOLID_NOT_SOLID );
SetActualSize( m_flWidth, m_flHeight );
m_fScreenFlags.Set( VGUI_SCREEN_ACTIVE );
m_takedamage = DAMAGE_NO;
AddFlag( FL_NOTARGET );
}
//-----------------------------------------------------------------------------
// Spawn...
//-----------------------------------------------------------------------------
void CVGuiScreen::Activate()
{
BaseClass::Activate();
if ( m_nOverlayMaterial == OVERLAY_MATERIAL_INVALID_STRING && m_strOverlayMaterial != NULL_STRING )
{
SetOverlayMaterial( STRING(m_strOverlayMaterial) );
}
}
void CVGuiScreen::OnRestore()
{
UpdateTransmitState();
BaseClass::OnRestore();
}
void CVGuiScreen::SetAttachmentIndex( int nIndex )
{
m_nAttachmentIndex = nIndex;
}
void CVGuiScreen::SetOverlayMaterial( const char *pMaterial )
{
int iMaterial = GetMaterialIndex( pMaterial );
if ( iMaterial == 0 )
{
m_nOverlayMaterial = OVERLAY_MATERIAL_INVALID_STRING;
}
else
{
m_nOverlayMaterial = iMaterial;
}
}
bool CVGuiScreen::IsActive() const
{
return (m_fScreenFlags & VGUI_SCREEN_ACTIVE) != 0;
}
void CVGuiScreen::SetActive( bool bActive )
{
if (bActive != IsActive())
{
if (!bActive)
{
m_fScreenFlags &= ~VGUI_SCREEN_ACTIVE;
}
else
{
m_fScreenFlags.Set( m_fScreenFlags | VGUI_SCREEN_ACTIVE );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CVGuiScreen::IsAttachedToViewModel() const
{
return (m_fScreenFlags & VGUI_SCREEN_ATTACHED_TO_VIEWMODEL) != 0;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bAttached -
//-----------------------------------------------------------------------------
void CVGuiScreen::SetAttachedToViewModel( bool bAttached )
{
if (bAttached != IsActive())
{
if (!bAttached)
{
m_fScreenFlags &= ~VGUI_SCREEN_ATTACHED_TO_VIEWMODEL;
}
else
{
m_fScreenFlags.Set( m_fScreenFlags | VGUI_SCREEN_ATTACHED_TO_VIEWMODEL );
// attached screens have different transmit rules
DispatchUpdateTransmitState();
}
// attached screens have different transmit rules
DispatchUpdateTransmitState();
}
}
void CVGuiScreen::SetTransparency( bool bTransparent )
{
if (!bTransparent)
{
m_fScreenFlags &= ~VGUI_SCREEN_TRANSPARENT;
}
else
{
m_fScreenFlags.Set( m_fScreenFlags | VGUI_SCREEN_TRANSPARENT );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVGuiScreen::InputSetActive( inputdata_t &inputdata )
{
SetActive( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVGuiScreen::InputSetInactive( inputdata_t &inputdata )
{
SetActive( false );
}
bool CVGuiScreen::IsVisibleOnlyToTeammates() const
{
return (m_fScreenFlags & VGUI_SCREEN_VISIBLE_TO_TEAMMATES) != 0;
}
void CVGuiScreen::MakeVisibleOnlyToTeammates( bool bActive )
{
if (bActive != IsVisibleOnlyToTeammates())
{
if (!bActive)
{
m_fScreenFlags &= ~VGUI_SCREEN_VISIBLE_TO_TEAMMATES;
}
else
{
m_fScreenFlags.Set( m_fScreenFlags | VGUI_SCREEN_VISIBLE_TO_TEAMMATES );
}
}
}
bool CVGuiScreen::IsVisibleToTeam( int nTeam )
{
// FIXME: Should this maybe go into a derived class of some sort?
// Don't bother with screens on the wrong team
if ( IsVisibleOnlyToTeammates() && (nTeam > 0) )
{
// Hmmm... sort of a hack...
CBaseEntity *pOwner = GetOwnerEntity();
if ( pOwner && (nTeam != pOwner->GetTeamNumber()) )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Screens attached to view models only go to client if viewmodel is being sent, too.
// Input : *recipient -
// *pvs -
// clientArea -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
int CVGuiScreen::UpdateTransmitState()
{
if ( IsAttachedToViewModel() )
{
// only send to the owner, or someone spectating the owner.
return SetTransmitState( FL_EDICT_FULLCHECK );
}
else if ( GetMoveParent() )
{
// Let the parent object trigger the send. This is more efficient than having it call CBaseEntity::ShouldTransmit
// for all the vgui screens in the map.
return SetTransmitState( FL_EDICT_PVSCHECK );
}
else
{
return BaseClass::UpdateTransmitState();
}
}
int CVGuiScreen::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
Assert( IsAttachedToViewModel() );
CBaseEntity *pViewModel = GetOwnerEntity();
if ( pViewModel )
{
return pViewModel->ShouldTransmit( pInfo );
}
return BaseClass::ShouldTransmit( pInfo );
}
//-----------------------------------------------------------------------------
// Convert the panel name into an integer
//-----------------------------------------------------------------------------
void CVGuiScreen::SetPanelName( const char *pPanelName )
{
m_nPanelName = g_pStringTableVguiScreen->AddString( CBaseEntity::IsServer(), pPanelName );
}
const char *CVGuiScreen::GetPanelName() const
{
return g_pStringTableVguiScreen->GetString( m_nPanelName );
}
//-----------------------------------------------------------------------------
// Sets the screen size + resolution
//-----------------------------------------------------------------------------
void CVGuiScreen::SetActualSize( float flWidth, float flHeight )
{
m_flWidth = flWidth;
m_flHeight = flHeight;
Vector mins, maxs;
mins.Init( 0.0f, 0.0f, -0.1f );
maxs.Init( 0.0f, 0.0f, 0.1f );
if (flWidth > 0)
maxs.x = flWidth;
else
mins.x = flWidth;
if (flHeight > 0)
maxs.y = flHeight;
else
mins.y = flHeight;
UTIL_SetSize( this, mins, maxs );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CVGuiScreen::SetPlayerOwner( CBasePlayer *pPlayer, bool bOwnerOnlyInput /* = false */ )
{
m_hPlayerOwner = pPlayer;
if ( bOwnerOnlyInput )
{
m_fScreenFlags.Set( VGUI_SCREEN_ONLY_USABLE_BY_OWNER );
}
}
//-----------------------------------------------------------------------------
// Precaches a vgui screen
//-----------------------------------------------------------------------------
void PrecacheVGuiScreen( const char *pScreenType )
{
g_pStringTableVguiScreen->AddString( CBaseEntity::IsServer(), pScreenType );
}
//-----------------------------------------------------------------------------
// Creates a vgui screen, attaches it to another player
//-----------------------------------------------------------------------------
CVGuiScreen *CreateVGuiScreen( const char *pScreenClassname, const char *pScreenType, CBaseEntity *pAttachedTo, CBaseEntity *pOwner, int nAttachmentIndex )
{
Assert( pAttachedTo );
CVGuiScreen *pScreen = (CVGuiScreen *)CBaseEntity::Create( pScreenClassname, vec3_origin, vec3_angle, pAttachedTo );
pScreen->SetPanelName( pScreenType );
pScreen->FollowEntity( pAttachedTo );
pScreen->SetOwnerEntity( pOwner );
pScreen->SetAttachmentIndex( nAttachmentIndex );
return pScreen;
}
void DestroyVGuiScreen( CVGuiScreen *pVGuiScreen )
{
if (pVGuiScreen)
{
UTIL_Remove( pVGuiScreen );
}
}