1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2024-12-23 01:59:43 +08:00
hl2sdk/cl_dll/entity_client_tools.cpp

654 lines
19 KiB
C++

//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "toolframework/itoolentity.h"
#include "tier1/KeyValues.h"
#include "sprite.h"
#include "enginesprite.h"
#include "toolframework_client.h"
#pragma warning( disable: 4355 ) // warning C4355: 'this' : used in base member initializer list
class CClientTools;
void DrawSpriteModel( IClientEntity *baseentity, CEngineSprite *psprite,
const Vector &origin, float fscale, float frame,
int rendermode, int r, int g, int b, int a,
const Vector& forward, const Vector& right, const Vector& up, float flHDRColorScale = 1.0f );
float StandardGlowBlend( const pixelvis_queryparams_t &params, pixelvis_handle_t *queryHandle,
int rendermode, int renderfx, int alpha, float *pscale );
// Interface from engine to tools for manipulating entities
class CClientTools : public IClientTools, public IClientEntityListener
{
public:
CClientTools();
virtual HTOOLHANDLE AttachToEntity( EntitySearchResult entityToAttach );
virtual bool IsValidHandle( HTOOLHANDLE handle );
virtual int GetNumRecordables();
virtual HTOOLHANDLE GetRecordable( int index );
// Iterates through ALL entities (separate list for client vs. server)
virtual EntitySearchResult NextEntity( EntitySearchResult currentEnt );
// Use this to turn on/off the presence of an underlying game entity
virtual void SetEnabled( HTOOLHANDLE handle, bool enabled );
virtual void SetRecording( HTOOLHANDLE handle, bool recording );
virtual int GetModelIndex( HTOOLHANDLE handle );
virtual const char* GetModelName ( HTOOLHANDLE handle );
virtual const char* GetClassname ( HTOOLHANDLE handle );
virtual HTOOLHANDLE GetToolHandleForEntityByIndex( int entindex );
virtual void AddClientRenderable( IClientRenderable *pRenderable, int renderGroup );
virtual void RemoveClientRenderable( IClientRenderable *pRenderable );
virtual void SetRenderGroup( IClientRenderable *pRenderable, int renderGroup );
virtual void MarkClientRenderableDirty( IClientRenderable *pRenderable );
virtual bool DrawSprite( IClientRenderable *pRenderable,
float scale, float frame,
int rendermode, int renderfx,
const Color &color, int *pVisHandle );
virtual bool GetLocalPlayerEyePosition( Vector& org, QAngle& ang, float &fov );
virtual EntitySearchResult GetLocalPlayer();
virtual ClientShadowHandle_t CreateShadow( CBaseHandle h, int nFlags );
virtual void DestroyShadow( ClientShadowHandle_t h );
virtual void AddToDirtyShadowList( ClientShadowHandle_t h, bool force = false );
virtual void MarkRenderToTextureShadowDirty( ClientShadowHandle_t h );
// Global toggle for recording
virtual void EnableRecordingMode( bool bEnable );
virtual bool IsInRecordingMode() const;
// Trigger a temp entity
virtual void TriggerTempEntity( KeyValues *pKeyValues );
// get owning weapon (for viewmodels)
virtual int GetOwningWeaponEntIndex( int entindex );
virtual int GetEntIndex( EntitySearchResult entityToAttach );
virtual int FindGlobalFlexcontroller( char const *name );
virtual char const *GetGlobalFlexControllerName( int idx );
// helper for traversing ownership hierarchy
virtual EntitySearchResult GetOwnerEntity( EntitySearchResult currentEnt );
// common and useful types to query for hierarchically
virtual bool IsPlayer( EntitySearchResult entityToAttach );
virtual bool IsBaseCombatCharacter( EntitySearchResult entityToAttach );
virtual bool IsNPC( EntitySearchResult entityToAttach );
virtual Vector GetAbsOrigin( HTOOLHANDLE handle );
virtual QAngle GetAbsAngles( HTOOLHANDLE handle );
public:
C_BaseEntity *LookupEntity( HTOOLHANDLE handle );
// IClientEntityListener methods
void OnEntityDeleted( C_BaseEntity *pEntity );
void OnEntityCreated( C_BaseEntity *pEntity );
private:
void OnRemoveEntity( CBaseEntity *ent );
static int s_nNextHandle;
struct HToolEntry_t
{
HToolEntry_t() : m_Handle( 0 ) {}
HToolEntry_t( int handle, C_BaseEntity *pEntity = NULL )
: m_Handle( handle ), m_hEntity( pEntity )
{
if ( pEntity )
{
m_hEntity->SetToolHandle( m_Handle );
}
}
int m_Handle;
EHANDLE m_hEntity;
};
static bool HandleLessFunc( const HToolEntry_t& lhs, const HToolEntry_t& rhs )
{
return lhs.m_Handle < rhs.m_Handle;
}
CUtlRBTree< HToolEntry_t > m_Handles;
CUtlVector< int > m_ActiveHandles;
bool m_bInRecordingMode;
bool m_bWTF;
};
CClientTools::CClientTools() : m_Handles( 0, 0, HandleLessFunc )
{
m_bInRecordingMode = false;
cl_entitylist->AddListenerEntity( this );
}
int CClientTools::s_nNextHandle = 1;
//-----------------------------------------------------------------------------
// Global toggle for recording
//-----------------------------------------------------------------------------
void CClientTools::EnableRecordingMode( bool bEnable )
{
m_bInRecordingMode = bEnable;
}
bool CClientTools::IsInRecordingMode() const
{
return m_bInRecordingMode;
}
//-----------------------------------------------------------------------------
// Trigger a temp entity
//-----------------------------------------------------------------------------
void CClientTools::TriggerTempEntity( KeyValues *pKeyValues )
{
te->TriggerTempEntity( pKeyValues );
}
//-----------------------------------------------------------------------------
// get owning weapon (for viewmodels)
//-----------------------------------------------------------------------------
int CClientTools::GetOwningWeaponEntIndex( int entindex )
{
C_BaseEntity *pEnt = C_BaseEntity::Instance( entindex );
C_BaseViewModel *pViewModel = dynamic_cast< C_BaseViewModel* >( pEnt );
if ( pViewModel )
{
C_BaseCombatWeapon *pWeapon = pViewModel->GetOwningWeapon();
if ( pWeapon )
{
return pWeapon->entindex();
}
}
return -1;
}
int CClientTools::GetEntIndex( EntitySearchResult entityToAttach )
{
C_BaseEntity *ent = reinterpret_cast< C_BaseEntity * >( entityToAttach );
return ent ? ent->entindex() : 0;
}
void CClientTools::AddClientRenderable( IClientRenderable *pRenderable, int renderGroup )
{
Assert( pRenderable );
cl_entitylist->AddNonNetworkableEntity( pRenderable->GetIClientUnknown() );
ClientRenderHandle_t handle = pRenderable->RenderHandle();
if ( INVALID_CLIENT_RENDER_HANDLE == handle )
{
// create new renderer handle
ClientLeafSystem()->AddRenderable( pRenderable, (RenderGroup_t)renderGroup );
}
else
{
// handle already exists, just update group & origin
ClientLeafSystem()->SetRenderGroup( pRenderable->RenderHandle(), (RenderGroup_t)renderGroup );
ClientLeafSystem()->RenderableChanged( pRenderable->RenderHandle() );
}
}
void CClientTools::RemoveClientRenderable( IClientRenderable *pRenderable )
{
ClientRenderHandle_t handle = pRenderable->RenderHandle();
if( handle != INVALID_CLIENT_RENDER_HANDLE )
{
ClientLeafSystem()->RemoveRenderable( handle );
}
cl_entitylist->RemoveEntity( pRenderable->GetIClientUnknown()->GetRefEHandle() );
}
void CClientTools::MarkClientRenderableDirty( IClientRenderable *pRenderable )
{
ClientRenderHandle_t handle = pRenderable->RenderHandle();
if ( INVALID_CLIENT_RENDER_HANDLE != handle )
{
// handle already exists, just update group & origin
ClientLeafSystem()->RenderableChanged( pRenderable->RenderHandle() );
}
}
void CClientTools::SetRenderGroup( IClientRenderable *pRenderable, int renderGroup )
{
ClientRenderHandle_t handle = pRenderable->RenderHandle();
if ( INVALID_CLIENT_RENDER_HANDLE == handle )
{
// create new renderer handle
ClientLeafSystem()->AddRenderable( pRenderable, (RenderGroup_t)renderGroup );
}
else
{
// handle already exists, just update group & origin
ClientLeafSystem()->SetRenderGroup( pRenderable->RenderHandle(), (RenderGroup_t)renderGroup );
ClientLeafSystem()->RenderableChanged( pRenderable->RenderHandle() );
}
}
bool CClientTools::DrawSprite( IClientRenderable *pRenderable, float scale, float frame, int rendermode, int renderfx, const Color &color, int *pVisHandle )
{
Vector origin = pRenderable->GetRenderOrigin();
QAngle angles = pRenderable->GetRenderAngles();
// Get extra data
CEngineSprite *psprite = (CEngineSprite *)modelinfo->GetModelExtraData( pRenderable->GetModel() );
if ( !psprite )
return false;
// Get orthonormal bases for current view - re-align to current camera (vs. recorded camera)
Vector forward, right, up;
C_SpriteRenderer::GetSpriteAxes( ( C_SpriteRenderer::SPRITETYPE )psprite->GetOrientation(), origin, angles, forward, right, up );
int r = color.r();
int g = color.g();
int b = color.b();
float oldBlend = render->GetBlend();
if ( rendermode != kRenderNormal )
{
// kRenderGlow and kRenderWorldGlow have a special blending function
if (( rendermode == kRenderGlow ) || ( rendermode == kRenderWorldGlow ))
{
pixelvis_queryparams_t params;
params.Init( origin );
float blend = oldBlend * StandardGlowBlend( params, ( pixelvis_handle_t* )pVisHandle, rendermode, renderfx, color.a(), &scale );
if ( blend <= 0.0f )
return false;
//Fade out the sprite depending on distance from the view origin.
r *= blend;
g *= blend;
b *= blend;
render->SetBlend( blend );
}
}
DrawSpriteModel( ( IClientEntity* )pRenderable, psprite, origin, scale, frame, rendermode, r, g, b, color.a(), forward, right, up );
if (( rendermode == kRenderGlow ) || ( rendermode == kRenderWorldGlow ))
{
render->SetBlend( oldBlend );
}
return true;
}
HTOOLHANDLE CClientTools::AttachToEntity( EntitySearchResult entityToAttach )
{
C_BaseEntity *ent = reinterpret_cast< C_BaseEntity * >( entityToAttach );
if ( !ent )
return (HTOOLHANDLE)0;
HTOOLHANDLE curHandle = ent->GetToolHandle();
if ( curHandle != 0 )
return curHandle; // Already attaached
HToolEntry_t newHandle( s_nNextHandle++, ent );
m_Handles.Insert( newHandle );
m_ActiveHandles.AddToTail( newHandle.m_Handle );
return (HTOOLHANDLE)newHandle.m_Handle;
}
void CClientTools::OnRemoveEntity( C_BaseEntity *ent )
{
if ( !ent )
{
Assert( 0 );
return;
}
HTOOLHANDLE handle = ent->GetToolHandle();
ent->SetToolHandle( (HTOOLHANDLE)0 );
if ( handle == (HTOOLHANDLE)0 )
{
Assert( 0 );
return;
}
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
{
Assert( 0 );
return;
}
// Send deletion message to tool interface
if ( m_bInRecordingMode )
{
KeyValues *kv = new KeyValues( "deleted" );
ToolFramework_PostToolMessage( handle, kv );
kv->deleteThis();
}
m_Handles.RemoveAt( idx );
m_ActiveHandles.FindAndRemove( handle );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : handle -
// Output : C_BaseEntity
//-----------------------------------------------------------------------------
C_BaseEntity *CClientTools::LookupEntity( HTOOLHANDLE handle )
{
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
return NULL;
return m_Handles[ idx ].m_hEntity;
}
int CClientTools::GetNumRecordables()
{
return m_ActiveHandles.Count();
}
HTOOLHANDLE CClientTools::GetRecordable( int index )
{
if ( index < 0 || index >= m_ActiveHandles.Count() )
{
Assert( 0 );
return (HTOOLHANDLE)0;
}
return m_ActiveHandles[ index ];
}
//-----------------------------------------------------------------------------
// Iterates through ALL entities (separate list for client vs. server)
//-----------------------------------------------------------------------------
EntitySearchResult CClientTools::NextEntity( EntitySearchResult currentEnt )
{
C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
if ( ent == NULL )
{
ent = cl_entitylist->FirstBaseEntity();
}
else
{
ent = cl_entitylist->NextBaseEntity( ent );
}
return reinterpret_cast< EntitySearchResult >( ent );
}
//-----------------------------------------------------------------------------
// Use this to turn on/off the presence of an underlying game entity
//-----------------------------------------------------------------------------
void CClientTools::SetEnabled( HTOOLHANDLE handle, bool enabled )
{
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
return;
HToolEntry_t *slot = &m_Handles[ idx ];
Assert( slot );
if ( slot == NULL )
return;
C_BaseEntity *ent = slot->m_hEntity.Get();
if ( ent == NULL || ent->entindex() == 0 )
return; // Don't disable/enable the "world"
ent->EnableInToolView( enabled );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClientTools::SetRecording( HTOOLHANDLE handle, bool recording )
{
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
return;
HToolEntry_t &entry = m_Handles[ idx ];
if ( entry.m_hEntity )
{
entry.m_hEntity->SetToolRecording( recording );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CClientTools::GetModelIndex( HTOOLHANDLE handle )
{
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
return NULL;
HToolEntry_t &entry = m_Handles[ idx ];
if ( entry.m_hEntity )
{
return entry.m_hEntity->GetModelIndex();
}
Assert( 0 );
return 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char* CClientTools::GetModelName( HTOOLHANDLE handle )
{
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
return NULL;
HToolEntry_t &entry = m_Handles[ idx ];
if ( entry.m_hEntity )
{
return STRING( entry.m_hEntity->GetModelName() );
}
Assert( 0 );
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char* CClientTools::GetClassname( HTOOLHANDLE handle )
{
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
return NULL;
HToolEntry_t &entry = m_Handles[ idx ];
if ( entry.m_hEntity )
{
return STRING( entry.m_hEntity->GetClassname() );
}
Assert( 0 );
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : handle -
//-----------------------------------------------------------------------------
bool CClientTools::IsValidHandle( HTOOLHANDLE handle )
{
return m_Handles.Find( HToolEntry_t( handle ) ) != m_Handles.InvalidIndex();
}
void CClientTools::OnEntityDeleted( CBaseEntity *pEntity )
{
if ( pEntity && pEntity->GetToolHandle() != (HTOOLHANDLE)0 )
{
OnRemoveEntity( pEntity );
}
}
void CClientTools::OnEntityCreated( CBaseEntity *pEntity )
{
// It won't have a HTOOLHANDLE since it's new!!!
if ( m_bInRecordingMode )
{
// Send deletion message to tool interface
KeyValues *kv = new KeyValues( "created" );
kv->SetPtr( "entity", pEntity );
kv->SetInt( "index", pEntity->entindex() );
kv->SetInt( "client", 1 );
kv->SetString( "classname", pEntity->GetClassname() );
HTOOLHANDLE h = AttachToEntity( pEntity );
ToolFramework_PostToolMessage( h, kv );
kv->deleteThis();
}
}
HTOOLHANDLE CClientTools::GetToolHandleForEntityByIndex( int entindex )
{
C_BaseEntity *ent = C_BaseEntity::Instance( entindex );
if ( !ent )
return (HTOOLHANDLE)0;
return ent->GetToolHandle();
}
EntitySearchResult CClientTools::GetLocalPlayer()
{
C_BasePlayer *p = C_BasePlayer::GetLocalPlayer();
return reinterpret_cast< EntitySearchResult >( p );
}
bool CClientTools::GetLocalPlayerEyePosition( Vector& org, QAngle& ang, float &fov )
{
C_BasePlayer *pl = C_BasePlayer::GetLocalPlayer();
if ( pl == NULL )
return false;
org = pl->EyePosition();
ang = pl->EyeAngles();
fov = pl->GetFOV();
return true;
}
//-----------------------------------------------------------------------------
// Create, destroy shadow
//-----------------------------------------------------------------------------
ClientShadowHandle_t CClientTools::CreateShadow( CBaseHandle h, int nFlags )
{
return g_pClientShadowMgr->CreateShadow( h, nFlags );
}
void CClientTools::DestroyShadow( ClientShadowHandle_t h )
{
g_pClientShadowMgr->DestroyShadow( h );
}
void CClientTools::AddToDirtyShadowList( ClientShadowHandle_t h, bool force )
{
g_pClientShadowMgr->AddToDirtyShadowList( h, force );
}
void CClientTools::MarkRenderToTextureShadowDirty( ClientShadowHandle_t h )
{
g_pClientShadowMgr->MarkRenderToTextureShadowDirty( h );
}
int CClientTools::FindGlobalFlexcontroller( char const *name )
{
return C_BaseFlex::AddGlobalFlexController( (char *)name );
}
char const *CClientTools::GetGlobalFlexControllerName( int idx )
{
return C_BaseFlex::GetGlobalFlexControllerName( idx );
}
//-----------------------------------------------------------------------------
// helper for traversing ownership hierarchy
//-----------------------------------------------------------------------------
EntitySearchResult CClientTools::GetOwnerEntity( EntitySearchResult currentEnt )
{
C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
return ent ? ent->GetOwnerEntity() : NULL;
}
//-----------------------------------------------------------------------------
// common and useful types to query for hierarchically
//-----------------------------------------------------------------------------
bool CClientTools::IsPlayer( EntitySearchResult currentEnt )
{
C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
return ent ? ent->IsPlayer() : false;
}
bool CClientTools::IsBaseCombatCharacter( EntitySearchResult currentEnt )
{
C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
return ent ? ent->IsBaseCombatCharacter() : false;
}
bool CClientTools::IsNPC( EntitySearchResult currentEnt )
{
C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
return ent ? ent->IsNPC() : false;
}
Vector CClientTools::GetAbsOrigin( HTOOLHANDLE handle )
{
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
return vec3_origin;
HToolEntry_t &entry = m_Handles[ idx ];
if ( entry.m_hEntity )
{
return entry.m_hEntity->GetAbsOrigin();
}
Assert( 0 );
return vec3_origin;
}
QAngle CClientTools::GetAbsAngles( HTOOLHANDLE handle )
{
int idx = m_Handles.Find( HToolEntry_t( handle ) );
if ( idx == m_Handles.InvalidIndex() )
return vec3_angle;
HToolEntry_t &entry = m_Handles[ idx ];
if ( entry.m_hEntity )
{
return entry.m_hEntity->GetAbsAngles();
}
Assert( 0 );
return vec3_angle;
}
static CClientTools s_ClientTools;
IClientTools *clienttools = &s_ClientTools;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientTools, IClientTools, VCLIENTTOOLS_INTERFACE_VERSION, s_ClientTools );