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.

1174 lines
35 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "toolframework/itoolentity.h"
  8. #include "tier1/keyvalues.h"
  9. #include "Sprite.h"
  10. #include "enginesprite.h"
  11. #include "beamdraw.h"
  12. #include "toolframework_client.h"
  13. #include "particles/particles.h"
  14. #include "particle_parse.h"
  15. #include "rendertexture.h"
  16. #include "model_types.h"
  17. #include "vstdlib/ikeyvaluessystem.h"
  18. #ifdef PORTAL
  19. #include "portalrender.h"
  20. #include "c_portal_player.h"
  21. #endif
  22. // NOTE: This has to be the last file included!
  23. #include "tier0/memdbgon.h"
  24. #pragma warning( disable: 4355 ) // warning C4355: 'this' : used in base member initializer list
  25. class CClientTools;
  26. void DrawSpriteModel( IClientEntity *baseentity, CEngineSprite *psprite,
  27. const Vector &origin, float fscale, float frame,
  28. int rendermode, int r, int g, int b, int a,
  29. const Vector& forward, const Vector& right, const Vector& up, float flHDRColorScale = 1.0f );
  30. float StandardGlowBlend( const pixelvis_queryparams_t &params, pixelvis_handle_t *queryHandle,
  31. int rendermode, int renderfx, int alpha, float *pscale );
  32. void HandleGameEntityKeyValues( KeyValues *pKeyValues );
  33. // Interface from engine to tools for manipulating entities
  34. class CClientTools : public IClientTools, public IClientEntityListener
  35. {
  36. public:
  37. CClientTools();
  38. virtual HTOOLHANDLE AttachToEntity( EntitySearchResult entityToAttach );
  39. virtual void DetachFromEntity( EntitySearchResult entityToDetach );
  40. virtual EntitySearchResult GetEntity( HTOOLHANDLE handle );
  41. virtual bool IsValidHandle( HTOOLHANDLE handle );
  42. virtual int GetNumRecordables();
  43. virtual HTOOLHANDLE GetRecordable( int index );
  44. // Iterates through ALL entities (separate list for client vs. server)
  45. virtual EntitySearchResult NextEntity( EntitySearchResult currentEnt );
  46. // Use this to turn on/off the presence of an underlying game entity
  47. virtual void SetEnabled( HTOOLHANDLE handle, bool enabled );
  48. virtual void SetRecording( HTOOLHANDLE handle, bool recording );
  49. virtual bool ShouldRecord( HTOOLHANDLE handle );
  50. virtual int GetModelIndex( HTOOLHANDLE handle );
  51. virtual const char* GetModelName ( HTOOLHANDLE handle );
  52. virtual const char* GetClassname ( HTOOLHANDLE handle );
  53. virtual HTOOLHANDLE GetToolHandleForEntityByIndex( int entindex );
  54. virtual void AddClientRenderable( IClientRenderable *pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType );
  55. virtual void RemoveClientRenderable( IClientRenderable *pRenderable );
  56. virtual void SetTranslucencyType( IClientRenderable *pRenderable, RenderableTranslucencyType_t nType );
  57. virtual void MarkClientRenderableDirty( IClientRenderable *pRenderable );
  58. virtual bool DrawSprite( IClientRenderable *pRenderable,
  59. float scale, float frame,
  60. int rendermode, int renderfx,
  61. const Color &color, float flProxyRadius, int *pVisHandle );
  62. virtual void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color );
  63. virtual bool GetLocalPlayerEyePosition( Vector& org, QAngle& ang, float &fov );
  64. virtual EntitySearchResult GetLocalPlayer();
  65. virtual ClientShadowHandle_t CreateShadow( CBaseHandle h, int nFlags );
  66. virtual void DestroyShadow( ClientShadowHandle_t h );
  67. virtual ClientShadowHandle_t CreateFlashlight( const FlashlightState_t &lightState );
  68. virtual void DestroyFlashlight( ClientShadowHandle_t h );
  69. virtual void UpdateFlashlightState( ClientShadowHandle_t h, const FlashlightState_t &flashlightState );
  70. virtual void AddToDirtyShadowList( ClientShadowHandle_t h, bool force = false );
  71. virtual void MarkRenderToTextureShadowDirty( ClientShadowHandle_t h );
  72. virtual void UpdateProjectedTexture( ClientShadowHandle_t h, bool bForce );
  73. // Global toggle for recording
  74. virtual void EnableRecordingMode( bool bEnable );
  75. virtual bool IsInRecordingMode() const;
  76. // Trigger a temp entity
  77. virtual void TriggerTempEntity( KeyValues *pKeyValues );
  78. // get owning weapon (for viewmodels)
  79. virtual int GetOwningWeaponEntIndex( int entindex );
  80. virtual int GetEntIndex( EntitySearchResult entityToAttach );
  81. virtual int FindGlobalFlexcontroller( char const *name );
  82. virtual char const *GetGlobalFlexControllerName( int idx );
  83. // helper for traversing ownership hierarchy
  84. virtual EntitySearchResult GetOwnerEntity( EntitySearchResult currentEnt );
  85. // common and useful types to query for hierarchically
  86. virtual bool IsPlayer( EntitySearchResult entityToAttach );
  87. virtual bool IsCombatCharacter( EntitySearchResult entityToAttach );
  88. virtual bool IsNPC( EntitySearchResult entityToAttach );
  89. virtual bool IsRagdoll( EntitySearchResult currentEnt );
  90. virtual bool IsViewModel( EntitySearchResult entityToAttach );
  91. virtual bool IsViewModelOrAttachment( EntitySearchResult entityToAttach );
  92. virtual bool IsWeapon( EntitySearchResult entityToAttach );
  93. virtual bool IsSprite( EntitySearchResult entityToAttach );
  94. virtual bool IsProp( EntitySearchResult entityToAttach );
  95. virtual bool IsBrush( EntitySearchResult entityToAttach );
  96. virtual Vector GetAbsOrigin( HTOOLHANDLE handle );
  97. virtual QAngle GetAbsAngles( HTOOLHANDLE handle );
  98. virtual void ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen );
  99. // ParticleSystem iteration, query, modification
  100. virtual ParticleSystemSearchResult NextParticleSystem( ParticleSystemSearchResult sr );
  101. virtual void SetRecording( ParticleSystemSearchResult sr, bool bRecord );
  102. // Sends a mesage from the tool to the client
  103. virtual void PostToolMessage( KeyValues *pKeyValues );
  104. // Indicates whether the client should render particle systems
  105. virtual void EnableParticleSystems( bool bEnable );
  106. // Is the game rendering in 3rd person mode?
  107. virtual bool IsRenderingThirdPerson() const;
  108. public:
  109. C_BaseEntity *LookupEntity( HTOOLHANDLE handle );
  110. // IClientEntityListener methods
  111. void OnEntityDeleted( C_BaseEntity *pEntity );
  112. void OnEntityCreated( C_BaseEntity *pEntity );
  113. private:
  114. struct HToolEntry_t
  115. {
  116. HToolEntry_t() : m_Handle( 0 ) {}
  117. explicit HToolEntry_t( int handle, C_BaseEntity *pEntity = NULL )
  118. : m_Handle( handle ), m_hEntity( pEntity )
  119. {
  120. if ( pEntity )
  121. {
  122. m_hEntity->SetToolHandle( m_Handle );
  123. }
  124. }
  125. int m_Handle;
  126. EHANDLE m_hEntity;
  127. };
  128. static int s_nNextHandle;
  129. static bool HandleLessFunc( const HToolEntry_t& lhs, const HToolEntry_t& rhs )
  130. {
  131. return lhs.m_Handle < rhs.m_Handle;
  132. }
  133. CUtlRBTree< HToolEntry_t > m_Handles;
  134. CUtlVector< int > m_ActiveHandles;
  135. bool m_bInRecordingMode;
  136. };
  137. //-----------------------------------------------------------------------------
  138. // Statics
  139. //-----------------------------------------------------------------------------
  140. int CClientTools::s_nNextHandle = 1;
  141. //-----------------------------------------------------------------------------
  142. // Singleton instance
  143. //-----------------------------------------------------------------------------
  144. static CClientTools s_ClientTools;
  145. IClientTools *clienttools = &s_ClientTools;
  146. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientTools, IClientTools, VCLIENTTOOLS_INTERFACE_VERSION, s_ClientTools );
  147. //-----------------------------------------------------------------------------
  148. // Constructor
  149. //-----------------------------------------------------------------------------
  150. CClientTools::CClientTools() : m_Handles( 0, 0, HandleLessFunc )
  151. {
  152. m_bInRecordingMode = false;
  153. cl_entitylist->AddListenerEntity( this );
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Global toggle for recording
  157. //-----------------------------------------------------------------------------
  158. void CClientTools::EnableRecordingMode( bool bEnable )
  159. {
  160. m_bInRecordingMode = bEnable;
  161. }
  162. bool CClientTools::IsInRecordingMode() const
  163. {
  164. return m_bInRecordingMode;
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Trigger a temp entity
  168. //-----------------------------------------------------------------------------
  169. void CClientTools::TriggerTempEntity( KeyValues *pKeyValues )
  170. {
  171. te->TriggerTempEntity( pKeyValues );
  172. }
  173. //-----------------------------------------------------------------------------
  174. // get owning weapon (for viewmodels)
  175. //-----------------------------------------------------------------------------
  176. int CClientTools::GetOwningWeaponEntIndex( int entindex )
  177. {
  178. C_BaseEntity *pEnt = C_BaseEntity::Instance( entindex );
  179. C_BaseViewModel *pViewModel = ToBaseViewModel( pEnt );
  180. if ( pViewModel )
  181. {
  182. C_BaseCombatWeapon *pWeapon = pViewModel->GetOwningWeapon();
  183. if ( pWeapon )
  184. {
  185. return pWeapon->entindex();
  186. }
  187. }
  188. return -1;
  189. }
  190. int CClientTools::GetEntIndex( EntitySearchResult entityToAttach )
  191. {
  192. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity * >( entityToAttach );
  193. return ent ? ent->entindex() : 0;
  194. }
  195. void CClientTools::AddClientRenderable( IClientRenderable *pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType )
  196. {
  197. Assert( pRenderable );
  198. cl_entitylist->AddNonNetworkableEntity( pRenderable->GetIClientUnknown() );
  199. ClientRenderHandle_t handle = pRenderable->RenderHandle();
  200. if ( INVALID_CLIENT_RENDER_HANDLE == handle )
  201. {
  202. // create new renderer handle
  203. ClientLeafSystem()->AddRenderable( pRenderable, bRenderWithViewModels, nType, nModelType );
  204. }
  205. else
  206. {
  207. // handle already exists, just update group & origin
  208. ClientLeafSystem()->RenderWithViewModels( pRenderable->RenderHandle(), bRenderWithViewModels );
  209. ClientLeafSystem()->SetTranslucencyType( pRenderable->RenderHandle(), nType );
  210. ClientLeafSystem()->SetModelType( pRenderable->RenderHandle(), nModelType );
  211. ClientLeafSystem()->RenderableChanged( pRenderable->RenderHandle() );
  212. }
  213. }
  214. void CClientTools::RemoveClientRenderable( IClientRenderable *pRenderable )
  215. {
  216. ClientRenderHandle_t handle = pRenderable->RenderHandle();
  217. if( handle != INVALID_CLIENT_RENDER_HANDLE )
  218. {
  219. ClientLeafSystem()->RemoveRenderable( handle );
  220. }
  221. cl_entitylist->RemoveEntity( pRenderable->GetIClientUnknown()->GetRefEHandle() );
  222. }
  223. void CClientTools::MarkClientRenderableDirty( IClientRenderable *pRenderable )
  224. {
  225. ClientRenderHandle_t handle = pRenderable->RenderHandle();
  226. if ( INVALID_CLIENT_RENDER_HANDLE != handle )
  227. {
  228. // handle already exists, just update group & origin
  229. ClientLeafSystem()->RenderableChanged( pRenderable->RenderHandle() );
  230. }
  231. }
  232. void CClientTools::SetTranslucencyType( IClientRenderable *pRenderable, RenderableTranslucencyType_t nType )
  233. {
  234. ClientLeafSystem()->SetTranslucencyType( pRenderable->RenderHandle(), nType );
  235. }
  236. void CClientTools::DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color )
  237. {
  238. ::DrawSprite( vecOrigin, flWidth, flHeight, color );
  239. }
  240. bool CClientTools::DrawSprite( IClientRenderable *pRenderable, float scale, float frame, int rendermode, int renderfx, const Color &color, float flProxyRadius, int *pVisHandle )
  241. {
  242. Vector origin = pRenderable->GetRenderOrigin();
  243. QAngle angles = pRenderable->GetRenderAngles();
  244. // Get extra data
  245. CEngineSprite *psprite = (CEngineSprite *)modelinfo->GetModelExtraData( pRenderable->GetModel() );
  246. if ( !psprite )
  247. return false;
  248. // Get orthonormal bases for current view - re-align to current camera (vs. recorded camera)
  249. Vector forward, right, up;
  250. C_SpriteRenderer::GetSpriteAxes( ( C_SpriteRenderer::SPRITETYPE )psprite->GetOrientation(), origin, angles, forward, right, up );
  251. int r = color.r();
  252. int g = color.g();
  253. int b = color.b();
  254. float oldBlend = render->GetBlend();
  255. if ( rendermode != kRenderNormal )
  256. {
  257. // kRenderGlow and kRenderWorldGlow have a special blending function
  258. if (( rendermode == kRenderGlow ) || ( rendermode == kRenderWorldGlow ))
  259. {
  260. pixelvis_queryparams_t params;
  261. if ( flProxyRadius != 0.0f )
  262. {
  263. params.Init( origin, flProxyRadius );
  264. params.bSizeInScreenspace = true;
  265. }
  266. else
  267. {
  268. params.Init( origin );
  269. }
  270. float blend = oldBlend * StandardGlowBlend( params, ( pixelvis_handle_t* )pVisHandle, rendermode, renderfx, color.a(), &scale );
  271. if ( blend <= 0.0f )
  272. return false;
  273. //Fade out the sprite depending on distance from the view origin.
  274. r *= blend;
  275. g *= blend;
  276. b *= blend;
  277. render->SetBlend( blend );
  278. }
  279. }
  280. DrawSpriteModel( ( IClientEntity* )pRenderable, psprite, origin, scale, frame, rendermode, r, g, b, color.a(), forward, right, up );
  281. if (( rendermode == kRenderGlow ) || ( rendermode == kRenderWorldGlow ))
  282. {
  283. render->SetBlend( oldBlend );
  284. }
  285. return true;
  286. }
  287. HTOOLHANDLE CClientTools::AttachToEntity( EntitySearchResult entityToAttach )
  288. {
  289. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity * >( entityToAttach );
  290. Assert( ent );
  291. if ( !ent )
  292. return (HTOOLHANDLE)0;
  293. HTOOLHANDLE curHandle = ent->GetToolHandle();
  294. if ( curHandle != 0 )
  295. return curHandle; // Already attaached
  296. HToolEntry_t newHandle( s_nNextHandle++, ent );
  297. m_Handles.Insert( newHandle );
  298. m_ActiveHandles.AddToTail( newHandle.m_Handle );
  299. return (HTOOLHANDLE)newHandle.m_Handle;
  300. }
  301. void CClientTools::DetachFromEntity( EntitySearchResult entityToDetach )
  302. {
  303. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity * >( entityToDetach );
  304. Assert( ent );
  305. if ( !ent )
  306. return;
  307. HTOOLHANDLE handle = ent->GetToolHandle();
  308. ent->SetToolHandle( (HTOOLHANDLE)0 );
  309. if ( handle == (HTOOLHANDLE)0 )
  310. {
  311. Assert( 0 );
  312. return;
  313. }
  314. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  315. if ( idx == m_Handles.InvalidIndex() )
  316. {
  317. Assert( 0 );
  318. return;
  319. }
  320. m_Handles.RemoveAt( idx );
  321. m_ActiveHandles.FindAndRemove( handle );
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose:
  325. // Input : handle -
  326. // Output : C_BaseEntity
  327. //-----------------------------------------------------------------------------
  328. C_BaseEntity *CClientTools::LookupEntity( HTOOLHANDLE handle )
  329. {
  330. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  331. if ( idx == m_Handles.InvalidIndex() )
  332. return NULL;
  333. return m_Handles[ idx ].m_hEntity;
  334. }
  335. int CClientTools::GetNumRecordables()
  336. {
  337. return m_ActiveHandles.Count();
  338. }
  339. HTOOLHANDLE CClientTools::GetRecordable( int index )
  340. {
  341. if ( index < 0 || index >= m_ActiveHandles.Count() )
  342. {
  343. Assert( 0 );
  344. return (HTOOLHANDLE)0;
  345. }
  346. return m_ActiveHandles[ index ];
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Iterates through ALL entities (separate list for client vs. server)
  350. //-----------------------------------------------------------------------------
  351. EntitySearchResult CClientTools::NextEntity( EntitySearchResult currentEnt )
  352. {
  353. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  354. if ( ent == NULL )
  355. {
  356. ent = cl_entitylist->FirstBaseEntity();
  357. }
  358. else
  359. {
  360. ent = cl_entitylist->NextBaseEntity( ent );
  361. }
  362. return reinterpret_cast< EntitySearchResult >( ent );
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Use this to turn on/off the presence of an underlying game entity
  366. //-----------------------------------------------------------------------------
  367. void CClientTools::SetEnabled( HTOOLHANDLE handle, bool enabled )
  368. {
  369. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  370. if ( idx == m_Handles.InvalidIndex() )
  371. return;
  372. HToolEntry_t *slot = &m_Handles[ idx ];
  373. Assert( slot );
  374. if ( slot == NULL )
  375. return;
  376. C_BaseEntity *ent = slot->m_hEntity.Get();
  377. if ( ent == NULL || ent->entindex() == 0 )
  378. return; // Don't disable/enable the "world"
  379. ent->EnableInToolView( enabled );
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Purpose:
  383. //-----------------------------------------------------------------------------
  384. void CClientTools::SetRecording( HTOOLHANDLE handle, bool recording )
  385. {
  386. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  387. if ( idx == m_Handles.InvalidIndex() )
  388. return;
  389. HToolEntry_t &entry = m_Handles[ idx ];
  390. if ( entry.m_hEntity )
  391. {
  392. entry.m_hEntity->SetToolRecording( recording );
  393. }
  394. }
  395. bool CClientTools::ShouldRecord( HTOOLHANDLE handle )
  396. {
  397. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  398. if ( idx == m_Handles.InvalidIndex() )
  399. return false;
  400. HToolEntry_t &entry = m_Handles[ idx ];
  401. return entry.m_hEntity && entry.m_hEntity->ShouldRecordInTools();
  402. }
  403. //-----------------------------------------------------------------------------
  404. // Purpose:
  405. //-----------------------------------------------------------------------------
  406. int CClientTools::GetModelIndex( HTOOLHANDLE handle )
  407. {
  408. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  409. if ( idx == m_Handles.InvalidIndex() )
  410. return NULL;
  411. HToolEntry_t &entry = m_Handles[ idx ];
  412. if ( entry.m_hEntity )
  413. {
  414. return entry.m_hEntity->GetModelIndex();
  415. }
  416. Assert( 0 );
  417. return 0;
  418. }
  419. //-----------------------------------------------------------------------------
  420. // Purpose:
  421. //-----------------------------------------------------------------------------
  422. const char* CClientTools::GetModelName( HTOOLHANDLE handle )
  423. {
  424. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  425. if ( idx == m_Handles.InvalidIndex() )
  426. return NULL;
  427. HToolEntry_t &entry = m_Handles[ idx ];
  428. if ( entry.m_hEntity )
  429. {
  430. return STRING( entry.m_hEntity->GetModelName() );
  431. }
  432. Assert( 0 );
  433. return NULL;
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose:
  437. //-----------------------------------------------------------------------------
  438. const char* CClientTools::GetClassname( HTOOLHANDLE handle )
  439. {
  440. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  441. if ( idx == m_Handles.InvalidIndex() )
  442. return NULL;
  443. HToolEntry_t &entry = m_Handles[ idx ];
  444. if ( entry.m_hEntity )
  445. {
  446. return STRING( entry.m_hEntity->GetClassname() );
  447. }
  448. Assert( 0 );
  449. return NULL;
  450. }
  451. EntitySearchResult CClientTools::GetEntity( HTOOLHANDLE handle )
  452. {
  453. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  454. if ( idx == m_Handles.InvalidIndex() )
  455. return reinterpret_cast< EntitySearchResult >( NULL );
  456. HToolEntry_t *slot = &m_Handles[ idx ];
  457. Assert( slot );
  458. if ( slot == NULL )
  459. return reinterpret_cast< EntitySearchResult >( NULL );
  460. C_BaseEntity *ent = slot->m_hEntity.Get();
  461. return reinterpret_cast< EntitySearchResult >( ent );
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Purpose:
  465. // Input : handle -
  466. //-----------------------------------------------------------------------------
  467. bool CClientTools::IsValidHandle( HTOOLHANDLE handle )
  468. {
  469. return m_Handles.Find( HToolEntry_t( handle ) ) != m_Handles.InvalidIndex();
  470. }
  471. void CClientTools::OnEntityDeleted( CBaseEntity *pEntity )
  472. {
  473. HTOOLHANDLE handle = pEntity ? pEntity->GetToolHandle() : (HTOOLHANDLE)0;
  474. if ( handle == (HTOOLHANDLE)0 )
  475. return;
  476. if ( m_bInRecordingMode )
  477. {
  478. // Send deletion message to tool interface
  479. KeyValues *kv = new KeyValues( "deleted" );
  480. ToolFramework_PostToolMessage( handle, kv );
  481. kv->deleteThis();
  482. }
  483. DetachFromEntity( pEntity );
  484. }
  485. void CClientTools::OnEntityCreated( CBaseEntity *pEntity )
  486. {
  487. if ( !ToolsEnabled() )
  488. return;
  489. HTOOLHANDLE h = AttachToEntity( pEntity );
  490. // Send deletion message to tool interface
  491. KeyValues *kv = new KeyValues( "created" );
  492. kv->SetPtr( "esr", ( void* )pEntity );
  493. ToolFramework_PostToolMessage( h, kv );
  494. kv->deleteThis();
  495. }
  496. HTOOLHANDLE CClientTools::GetToolHandleForEntityByIndex( int entindex )
  497. {
  498. C_BaseEntity *ent = C_BaseEntity::Instance( entindex );
  499. if ( !ent )
  500. return (HTOOLHANDLE)0;
  501. return ent->GetToolHandle();
  502. }
  503. EntitySearchResult CClientTools::GetLocalPlayer()
  504. {
  505. ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
  506. C_BasePlayer *p = C_BasePlayer::GetLocalPlayer();
  507. return reinterpret_cast< EntitySearchResult >( p );
  508. }
  509. bool CClientTools::GetLocalPlayerEyePosition( Vector& org, QAngle& ang, float &fov )
  510. {
  511. ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
  512. C_BasePlayer *pl = C_BasePlayer::GetLocalPlayer();
  513. if ( pl == NULL )
  514. return false;
  515. org = pl->EyePosition();
  516. ang = pl->EyeAngles();
  517. fov = pl->GetFOV();
  518. return true;
  519. }
  520. //-----------------------------------------------------------------------------
  521. // ParticleSystem iteration, query, modification
  522. //-----------------------------------------------------------------------------
  523. ParticleSystemSearchResult CClientTools::NextParticleSystem( ParticleSystemSearchResult sr )
  524. {
  525. CNewParticleEffect *pParticleEffect = NULL;
  526. if ( sr == NULL )
  527. {
  528. pParticleEffect = ParticleMgr()->FirstNewEffect();
  529. }
  530. else
  531. {
  532. pParticleEffect = ParticleMgr()->NextNewEffect( reinterpret_cast< CNewParticleEffect* >( sr ) );
  533. }
  534. return reinterpret_cast< ParticleSystemSearchResult >( pParticleEffect );
  535. }
  536. void CClientTools::SetRecording( ParticleSystemSearchResult sr, bool bRecord )
  537. {
  538. Assert( sr );
  539. if ( sr == NULL )
  540. return;
  541. CNewParticleEffect *pParticleEffect = reinterpret_cast< CNewParticleEffect* >( sr );
  542. pParticleEffect->SetToolRecording( bRecord );
  543. }
  544. //-----------------------------------------------------------------------------
  545. // Create, destroy shadow
  546. //-----------------------------------------------------------------------------
  547. ClientShadowHandle_t CClientTools::CreateShadow( CBaseHandle h, int nFlags )
  548. {
  549. return g_pClientShadowMgr->CreateShadow( h, nFlags, NULL );
  550. }
  551. void CClientTools::DestroyShadow( ClientShadowHandle_t h )
  552. {
  553. g_pClientShadowMgr->DestroyShadow( h );
  554. }
  555. ClientShadowHandle_t CClientTools::CreateFlashlight( const FlashlightState_t &lightState )
  556. {
  557. return g_pClientShadowMgr->CreateFlashlight( lightState );
  558. }
  559. void CClientTools::DestroyFlashlight( ClientShadowHandle_t h )
  560. {
  561. g_pClientShadowMgr->DestroyFlashlight( h );
  562. }
  563. void CClientTools::UpdateFlashlightState( ClientShadowHandle_t h, const FlashlightState_t &lightState )
  564. {
  565. g_pClientShadowMgr->UpdateFlashlightState( h, lightState );
  566. }
  567. void CClientTools::AddToDirtyShadowList( ClientShadowHandle_t h, bool force )
  568. {
  569. g_pClientShadowMgr->AddToDirtyShadowList( h, force );
  570. }
  571. void CClientTools::MarkRenderToTextureShadowDirty( ClientShadowHandle_t h )
  572. {
  573. g_pClientShadowMgr->MarkRenderToTextureShadowDirty( h );
  574. }
  575. void CClientTools::UpdateProjectedTexture( ClientShadowHandle_t h, bool bForce )
  576. {
  577. g_pClientShadowMgr->UpdateProjectedTexture( h, bForce );
  578. }
  579. int CClientTools::FindGlobalFlexcontroller( char const *name )
  580. {
  581. return C_BaseFlex::AddGlobalFlexController( (char *)name );
  582. }
  583. char const *CClientTools::GetGlobalFlexControllerName( int idx )
  584. {
  585. return C_BaseFlex::GetGlobalFlexControllerName( idx );
  586. }
  587. //-----------------------------------------------------------------------------
  588. // helper for traversing ownership hierarchy
  589. //-----------------------------------------------------------------------------
  590. EntitySearchResult CClientTools::GetOwnerEntity( EntitySearchResult currentEnt )
  591. {
  592. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  593. return ent ? ent->GetOwnerEntity() : NULL;
  594. }
  595. //-----------------------------------------------------------------------------
  596. // common and useful types to query for hierarchically
  597. //-----------------------------------------------------------------------------
  598. bool CClientTools::IsPlayer( EntitySearchResult currentEnt )
  599. {
  600. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  601. return ent ? ent->IsPlayer() : false;
  602. }
  603. bool CClientTools::IsCombatCharacter( EntitySearchResult currentEnt )
  604. {
  605. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  606. return ent ? ent->IsBaseCombatCharacter() : false;
  607. }
  608. bool CClientTools::IsNPC( EntitySearchResult currentEnt )
  609. {
  610. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  611. return ent ? ent->IsNPC() : false;
  612. }
  613. bool CClientTools::IsRagdoll( EntitySearchResult currentEnt )
  614. {
  615. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  616. C_BaseAnimating *pBaseAnimating = ent ? ent->GetBaseAnimating() : NULL;
  617. return pBaseAnimating ? pBaseAnimating->IsClientRagdoll() : false;
  618. }
  619. bool CClientTools::IsViewModel( EntitySearchResult currentEnt )
  620. {
  621. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  622. C_BaseAnimating *pBaseAnimating = ent ? ent->GetBaseAnimating() : NULL;
  623. return pBaseAnimating ? pBaseAnimating->IsViewModel() : false;
  624. }
  625. bool CClientTools::IsViewModelOrAttachment( EntitySearchResult currentEnt )
  626. {
  627. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  628. C_BaseAnimating *pBaseAnimating = ent ? ent->GetBaseAnimating() : NULL;
  629. return pBaseAnimating ? pBaseAnimating->IsViewModelOrAttachment() : false;
  630. }
  631. bool CClientTools::IsWeapon( EntitySearchResult currentEnt )
  632. {
  633. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  634. return ent ? ent->IsBaseCombatWeapon() : false;
  635. }
  636. bool CClientTools::IsSprite( EntitySearchResult currentEnt )
  637. {
  638. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  639. return ent ? ent->IsSprite() : false;
  640. }
  641. bool CClientTools::IsProp( EntitySearchResult currentEnt )
  642. {
  643. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  644. return ent ? ent->IsProp() : false;
  645. }
  646. bool CClientTools::IsBrush( EntitySearchResult currentEnt )
  647. {
  648. C_BaseEntity *ent = reinterpret_cast< C_BaseEntity* >( currentEnt );
  649. return ent ? ent->IsBrushModel() : false;
  650. }
  651. Vector CClientTools::GetAbsOrigin( HTOOLHANDLE handle )
  652. {
  653. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  654. if ( idx == m_Handles.InvalidIndex() )
  655. return vec3_origin;
  656. HToolEntry_t &entry = m_Handles[ idx ];
  657. if ( entry.m_hEntity )
  658. {
  659. return entry.m_hEntity->GetAbsOrigin();
  660. }
  661. Assert( 0 );
  662. return vec3_origin;
  663. }
  664. QAngle CClientTools::GetAbsAngles( HTOOLHANDLE handle )
  665. {
  666. int idx = m_Handles.Find( HToolEntry_t( handle ) );
  667. if ( idx == m_Handles.InvalidIndex() )
  668. return vec3_angle;
  669. HToolEntry_t &entry = m_Handles[ idx ];
  670. if ( entry.m_hEntity )
  671. {
  672. return entry.m_hEntity->GetAbsAngles();
  673. }
  674. Assert( 0 );
  675. return vec3_angle;
  676. }
  677. //-----------------------------------------------------------------------------
  678. // Sends a mesage from the tool to the client
  679. //-----------------------------------------------------------------------------
  680. void CClientTools::PostToolMessage( KeyValues *pKeyValues )
  681. {
  682. if ( !Q_stricmp( pKeyValues->GetName(), "QueryParticleManifest" ) )
  683. {
  684. // NOTE: This cannot be done during particle system init because tools aren't set up at that point
  685. CUtlVector<CUtlString> files;
  686. GetParticleManifest( files );
  687. int nCount = files.Count();
  688. for ( int i = 0; i < nCount; ++i )
  689. {
  690. char pTemp[256];
  691. Q_snprintf( pTemp, sizeof(pTemp), "%d", i );
  692. KeyValues *pSubKey = pKeyValues->FindKey( pTemp, true );
  693. pSubKey->SetString( "file", files[i] );
  694. }
  695. return;
  696. }
  697. if ( !Q_stricmp( pKeyValues->GetName(), "QueryMonitorTexture" ) )
  698. {
  699. pKeyValues->SetPtr( "texture", GetCameraTexture() );
  700. return;
  701. }
  702. #ifdef PORTAL
  703. if ( !Q_stricmp( pKeyValues->GetName(), "portals" ) )
  704. {
  705. g_pPortalRender->HandlePortalPlaybackMessage( pKeyValues );
  706. return;
  707. }
  708. if ( !Q_stricmp( pKeyValues->GetName(), "query CPortalRenderer" ) )
  709. {
  710. pKeyValues->SetInt( "IsRenderingPortal", g_pPortalRender->GetViewRecursionLevel() );
  711. return;
  712. }
  713. #endif
  714. if ( !Q_strcmp( pKeyValues->GetName(), "Game Entity KeyValues" ) )
  715. {
  716. HandleGameEntityKeyValues( pKeyValues );
  717. }
  718. }
  719. //-----------------------------------------------------------------------------
  720. // Indicates whether the client should render particle systems
  721. //-----------------------------------------------------------------------------
  722. void CClientTools::EnableParticleSystems( bool bEnable )
  723. {
  724. ParticleMgr()->RenderParticleSystems( bEnable );
  725. }
  726. //-----------------------------------------------------------------------------
  727. // Is the game rendering in 3rd person mode?
  728. //-----------------------------------------------------------------------------
  729. bool CClientTools::IsRenderingThirdPerson() const
  730. {
  731. ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
  732. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  733. if ( !pLocalPlayer )
  734. return false;
  735. return pLocalPlayer->ShouldDrawLocalPlayer();
  736. }
  737. //-----------------------------------------------------------------------------
  738. // Reload particle definitions
  739. //-----------------------------------------------------------------------------
  740. void CClientTools::ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen )
  741. {
  742. MDLCACHE_CRITICAL_SECTION(); // Copying particle attachment control points may end up needing to evaluate skeletons
  743. //////////////
  744. // Find any systems that depend on any system in the buffer
  745. // slow, but necessary if we want live reloads to work - and doesn't happen too often
  746. CUtlVector<CUtlString> systemNamesToReload;
  747. CUtlBuffer bufSystemsInBuffer(pBufData, nLen, CUtlBuffer::READ_ONLY);
  748. g_pParticleSystemMgr->GetParticleSystemsInBuffer( bufSystemsInBuffer, &systemNamesToReload );
  749. CUtlVector<CNewParticleEffect*> toReplaceEffects;
  750. CUtlVector<CUtlString> toReplaceNames;
  751. for( CNewParticleEffect *pEffect = ParticleMgr()->FirstNewEffect(); pEffect; pEffect = ParticleMgr()->NextNewEffect(pEffect) )
  752. {
  753. for( int i = 0; i < systemNamesToReload.Count(); ++i )
  754. {
  755. if ( pEffect->DependsOnSystem( systemNamesToReload[i] ) )
  756. {
  757. // only reload a given effect once
  758. if ( -1 == toReplaceEffects.Find(pEffect) )
  759. {
  760. toReplaceNames.AddToTail( pEffect->GetName() );
  761. toReplaceEffects.AddToTail( pEffect );
  762. }
  763. }
  764. }
  765. }
  766. CUtlVector<CNonDrawingParticleSystem*> toReplaceEffectsNonDrawing;
  767. CUtlVector<CUtlString> toReplaceNamesNonDrawing;
  768. for( CNonDrawingParticleSystem *i = ParticleMgr()->m_NonDrawingParticleSystems.Head(); i ; i = i->m_pNext )
  769. {
  770. for( int j = 0; j < systemNamesToReload.Count(); ++j )
  771. {
  772. if ( i->Get()->DependsOnSystem( systemNamesToReload[j] ) )
  773. {
  774. if ( -1 == toReplaceEffectsNonDrawing.Find( i ) )
  775. {
  776. toReplaceNamesNonDrawing.AddToTail( i->Get()->GetName() );
  777. toReplaceEffectsNonDrawing.AddToTail( i );
  778. }
  779. }
  780. }
  781. }
  782. //////////////
  783. // Load the data and stomp the old definitions
  784. CUtlBuffer bufReadParticleConfigFile(pBufData, nLen, CUtlBuffer::READ_ONLY);
  785. g_pParticleSystemMgr->ReadParticleConfigFile( bufReadParticleConfigFile, true );
  786. //////////////
  787. // Now replace all of the systems with their new versions
  788. Assert( toReplaceEffects.Count() == toReplaceNames.Count() );
  789. for( int i = 0; i < toReplaceNames.Count(); ++i )
  790. {
  791. CNewParticleEffect *pEffect = toReplaceEffects[i];
  792. pEffect->ReplaceWith( toReplaceNames[i] );
  793. }
  794. // update all the non-drawings ones
  795. for( int i = 0; i < toReplaceNamesNonDrawing.Count(); i++ )
  796. {
  797. CNonDrawingParticleSystem *pEffect = toReplaceEffectsNonDrawing[i];
  798. delete pEffect->m_pSystem;
  799. pEffect->m_pSystem = g_pParticleSystemMgr->CreateParticleCollection( toReplaceNamesNonDrawing[i] );
  800. }
  801. }
  802. CIFM_EntityKeyValuesHandler_AutoRegister::CIFM_EntityKeyValuesHandler_AutoRegister( const char *szHandlerID )
  803. : m_szHandlerID( szHandlerID )
  804. {
  805. #if defined( DBGFLAG_ASSERT )
  806. const CIFM_EntityKeyValuesHandler_AutoRegister *pWalk = s_pRegisteredHandlers;
  807. while( pWalk )
  808. {
  809. AssertMsg( strcmp( szHandlerID, pWalk->m_szHandlerID ) != 0, "Handler already registered for this ID" );
  810. pWalk = pWalk->m_pNext;
  811. }
  812. #endif
  813. m_pNext = s_pRegisteredHandlers;
  814. s_pRegisteredHandlers = this;
  815. }
  816. void CIFM_EntityKeyValuesHandler_AutoRegister::AllHandlers_PreUpdate( void )
  817. {
  818. CIFM_EntityKeyValuesHandler_AutoRegister *pWalk = s_pRegisteredHandlers;
  819. while( pWalk )
  820. {
  821. pWalk->HandleData_PreUpdate();
  822. pWalk = pWalk->m_pNext;
  823. }
  824. }
  825. void CIFM_EntityKeyValuesHandler_AutoRegister::FindAndCallHandler( const char *szHandlerID, KeyValues *pKeyValues )
  826. {
  827. CIFM_EntityKeyValuesHandler_AutoRegister *pWalk = s_pRegisteredHandlers;
  828. while( pWalk )
  829. {
  830. if( strcmp( szHandlerID, pWalk->m_szHandlerID ) == 0 )
  831. {
  832. pWalk->HandleData( pKeyValues );
  833. return;
  834. }
  835. pWalk = pWalk->m_pNext;
  836. }
  837. AssertMsg( false, "Unhandled NonConformantData update" );
  838. }
  839. void CIFM_EntityKeyValuesHandler_AutoRegister::AllHandlers_PostUpdate( void )
  840. {
  841. CIFM_EntityKeyValuesHandler_AutoRegister *pWalk = s_pRegisteredHandlers;
  842. while( pWalk )
  843. {
  844. pWalk->HandleData_PostUpdate();
  845. pWalk = pWalk->m_pNext;
  846. }
  847. }
  848. void CIFM_EntityKeyValuesHandler_AutoRegister::AllHandlers_RemoveAll( void )
  849. {
  850. CIFM_EntityKeyValuesHandler_AutoRegister *pWalk = s_pRegisteredHandlers;
  851. while( pWalk )
  852. {
  853. pWalk->HandleData_RemoveAll();
  854. pWalk = pWalk->m_pNext;
  855. }
  856. }
  857. CIFM_EntityKeyValuesHandler_AutoRegister *CIFM_EntityKeyValuesHandler_AutoRegister::s_pRegisteredHandlers;
  858. HKeySymbol CIFM_EntityKeyValuesHandler_AutoRegister::GetGameKeyValuesKeySymbol( void )
  859. {
  860. static HKeySymbol s_hNonConformantSymbol = KeyValuesSystem()->GetSymbolForString( GetGameKeyValuesKeyString() );
  861. return s_hNonConformantSymbol;
  862. }
  863. const char *CIFM_EntityKeyValuesHandler_AutoRegister::GetGameKeyValuesKeyString( void )
  864. {
  865. return "gamekeyvalues";
  866. }
  867. HKeySymbol CIFM_EntityKeyValuesHandler_AutoRegister::GetHandlerIDKeySymbol( void )
  868. {
  869. static HKeySymbol s_hHandlerIDSymbol = KeyValuesSystem()->GetSymbolForString( GetHandlerIDKeyString() );
  870. return s_hHandlerIDSymbol;
  871. }
  872. const char *CIFM_EntityKeyValuesHandler_AutoRegister::GetHandlerIDKeyString( void )
  873. {
  874. return "handlerID";
  875. }
  876. KeyValues *CIFM_EntityKeyValuesHandler_AutoRegister::FindOrCreateNonConformantKeyValues( KeyValues *pParentKV )
  877. {
  878. KeyValues *pReturn = pParentKV->FindKey( GetGameKeyValuesKeySymbol() );
  879. if( !pReturn )
  880. {
  881. pReturn = pParentKV->FindKey( GetGameKeyValuesKeyString(), true );
  882. }
  883. return pReturn;
  884. }
  885. void HandleGameEntityKeyValues( KeyValues *pKeyValues )
  886. {
  887. if( pKeyValues->GetBool( "RemoveAll", false ) )
  888. {
  889. CIFM_EntityKeyValuesHandler_AutoRegister::AllHandlers_RemoveAll();
  890. }
  891. else
  892. {
  893. HKeySymbol handlerIDsym = CIFM_EntityKeyValuesHandler_AutoRegister::GetHandlerIDKeySymbol();
  894. CIFM_EntityKeyValuesHandler_AutoRegister::AllHandlers_PreUpdate();
  895. for ( KeyValues *pCurr = pKeyValues->GetFirstTrueSubKey(); pCurr; pCurr = pCurr->GetNextTrueSubKey() )
  896. {
  897. const char *szHandler = pCurr->GetString( handlerIDsym, "" );
  898. CIFM_EntityKeyValuesHandler_AutoRegister::FindAndCallHandler( szHandler, pCurr );
  899. }
  900. CIFM_EntityKeyValuesHandler_AutoRegister::AllHandlers_PostUpdate();
  901. }
  902. }
  903. CIFM_EntityKeyValuesHandler_RecreateEntities::CIFM_EntityKeyValuesHandler_RecreateEntities( const char *szHandlerID )
  904. : CIFM_EntityKeyValuesHandler_AutoRegister( szHandlerID )
  905. {
  906. }
  907. void CIFM_EntityKeyValuesHandler_RecreateEntities::HandleData_PreUpdate( void )
  908. {
  909. for( int i = 0; i != m_PlaybackEntities.Count(); ++i )
  910. {
  911. m_PlaybackEntities[i].bTouched = false;
  912. }
  913. }
  914. void CIFM_EntityKeyValuesHandler_RecreateEntities::HandleData_PostUpdate( void )
  915. {
  916. for( int i = m_PlaybackEntities.Count(); --i >= 0; )
  917. {
  918. if( !m_PlaybackEntities[i].bTouched )
  919. {
  920. //not updated, clear it
  921. DestroyInstance( m_PlaybackEntities[i].pEntity );
  922. m_PlaybackEntities.FastRemove( i );
  923. }
  924. }
  925. }
  926. void CIFM_EntityKeyValuesHandler_RecreateEntities::HandleData( KeyValues *pKeyValues )
  927. {
  928. int iEntIndex = pKeyValues->GetInt( "entIndex", -1 );
  929. Assert( iEntIndex != -1 );
  930. if( iEntIndex == -1 )
  931. return;
  932. for( int i = 0; i != m_PlaybackEntities.Count(); ++i )
  933. {
  934. if( m_PlaybackEntities[i].iEntIndex == iEntIndex )
  935. {
  936. HandleInstance( m_PlaybackEntities[i].pEntity, pKeyValues );
  937. m_PlaybackEntities[i].bTouched = true;
  938. return;
  939. }
  940. }
  941. //didn't exist, create it.
  942. RecordedEntity_t temp;
  943. temp.iEntIndex = iEntIndex;
  944. temp.pEntity = CreateInstance();
  945. temp.bTouched = true;
  946. m_PlaybackEntities.AddToTail( temp );
  947. HandleInstance( temp.pEntity, pKeyValues );
  948. }
  949. void CIFM_EntityKeyValuesHandler_RecreateEntities::HandleData_RemoveAll( void )
  950. {
  951. for( int i = m_PlaybackEntities.Count(); --i >= 0; )
  952. {
  953. DestroyInstance( m_PlaybackEntities[i].pEntity );
  954. }
  955. m_PlaybackEntities.RemoveAll();
  956. }