PageRenderTime 1447ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/sp/src/game/client/c_baseentity.cpp

https://github.com/ValveSoftware/source-sdk-2013
C++ | 6487 lines | 4249 code | 1056 blank | 1182 comment | 733 complexity | ec902e6dc467d7e0e59ce71e46a3782c MD5 | raw file
Possible License(s): BSD-3-Clause
  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "c_baseentity.h"
  9. #include "prediction.h"
  10. #include "model_types.h"
  11. #include "iviewrender_beams.h"
  12. #include "dlight.h"
  13. #include "iviewrender.h"
  14. #include "view.h"
  15. #include "iefx.h"
  16. #include "c_team.h"
  17. #include "clientmode.h"
  18. #include "usercmd.h"
  19. #include "engine/IEngineSound.h"
  20. #include "engine/IEngineTrace.h"
  21. #include "engine/ivmodelinfo.h"
  22. #include "tier0/vprof.h"
  23. #include "fx_line.h"
  24. #include "interface.h"
  25. #include "materialsystem/imaterialsystem.h"
  26. #include "soundinfo.h"
  27. #include "mathlib/vmatrix.h"
  28. #include "isaverestore.h"
  29. #include "interval.h"
  30. #include "engine/ivdebugoverlay.h"
  31. #include "c_ai_basenpc.h"
  32. #include "apparent_velocity_helper.h"
  33. #include "c_baseanimatingoverlay.h"
  34. #include "tier1/KeyValues.h"
  35. #include "hltvcamera.h"
  36. #include "datacache/imdlcache.h"
  37. #include "toolframework/itoolframework.h"
  38. #include "toolframework_client.h"
  39. #include "decals.h"
  40. #include "cdll_bounded_cvars.h"
  41. #include "inetchannelinfo.h"
  42. #include "proto_version.h"
  43. // memdbgon must be the last include file in a .cpp file!!!
  44. #include "tier0/memdbgon.h"
  45. #ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT
  46. int g_nInterpolatedVarsChanged = 0;
  47. bool g_bRestoreInterpolatedVarValues = false;
  48. #endif
  49. static bool g_bWasSkipping = (bool)-1;
  50. static bool g_bWasThreaded =(bool)-1;
  51. static int g_nThreadModeTicks = 0;
  52. void cc_cl_interp_all_changed( IConVar *pConVar, const char *pOldString, float flOldValue )
  53. {
  54. ConVarRef var( pConVar );
  55. if ( var.GetInt() )
  56. {
  57. C_BaseEntityIterator iterator;
  58. C_BaseEntity *pEnt;
  59. while ( (pEnt = iterator.Next()) != NULL )
  60. {
  61. if ( pEnt->ShouldInterpolate() )
  62. {
  63. pEnt->AddToInterpolationList();
  64. }
  65. }
  66. }
  67. }
  68. static ConVar cl_extrapolate( "cl_extrapolate", "1", FCVAR_CHEAT, "Enable/disable extrapolation if interpolation history runs out." );
  69. static ConVar cl_interp_npcs( "cl_interp_npcs", "0.0", FCVAR_USERINFO, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)" );
  70. static ConVar cl_interp_all( "cl_interp_all", "0", 0, "Disable interpolation list optimizations.", 0, 0, 0, 0, cc_cl_interp_all_changed );
  71. ConVar r_drawmodeldecals( "r_drawmodeldecals", "1" );
  72. extern ConVar cl_showerror;
  73. int C_BaseEntity::m_nPredictionRandomSeed = -1;
  74. C_BasePlayer *C_BaseEntity::m_pPredictionPlayer = NULL;
  75. bool C_BaseEntity::s_bAbsQueriesValid = true;
  76. bool C_BaseEntity::s_bAbsRecomputationEnabled = true;
  77. bool C_BaseEntity::s_bInterpolate = true;
  78. bool C_BaseEntity::sm_bDisableTouchFuncs = false; // Disables PhysicsTouch and PhysicsStartTouch function calls
  79. static ConVar r_drawrenderboxes( "r_drawrenderboxes", "0", FCVAR_CHEAT );
  80. static bool g_bAbsRecomputationStack[8];
  81. static unsigned short g_iAbsRecomputationStackPos = 0;
  82. // All the entities that want Interpolate() called on them.
  83. static CUtlLinkedList<C_BaseEntity*, unsigned short> g_InterpolationList;
  84. static CUtlLinkedList<C_BaseEntity*, unsigned short> g_TeleportList;
  85. #if !defined( NO_ENTITY_PREDICTION )
  86. //-----------------------------------------------------------------------------
  87. // Purpose: Maintains a list of predicted or client created entities
  88. //-----------------------------------------------------------------------------
  89. class CPredictableList : public IPredictableList
  90. {
  91. public:
  92. virtual C_BaseEntity *GetPredictable( int slot );
  93. virtual int GetPredictableCount( void );
  94. protected:
  95. void AddToPredictableList( ClientEntityHandle_t add );
  96. void RemoveFromPredictablesList( ClientEntityHandle_t remove );
  97. private:
  98. CUtlVector< ClientEntityHandle_t > m_Predictables;
  99. friend class C_BaseEntity;
  100. };
  101. // Create singleton
  102. static CPredictableList g_Predictables;
  103. IPredictableList *predictables = &g_Predictables;
  104. //-----------------------------------------------------------------------------
  105. // Purpose: Add entity to list
  106. // Input : add -
  107. // Output : int
  108. //-----------------------------------------------------------------------------
  109. void CPredictableList::AddToPredictableList( ClientEntityHandle_t add )
  110. {
  111. // This is a hack to remap slot to index
  112. if ( m_Predictables.Find( add ) != m_Predictables.InvalidIndex() )
  113. {
  114. return;
  115. }
  116. // Add to general list
  117. m_Predictables.AddToTail( add );
  118. // Maintain sort order by entindex
  119. int count = m_Predictables.Size();
  120. if ( count < 2 )
  121. return;
  122. int i, j;
  123. for ( i = 0; i < count; i++ )
  124. {
  125. for ( j = i + 1; j < count; j++ )
  126. {
  127. ClientEntityHandle_t h1 = m_Predictables[ i ];
  128. ClientEntityHandle_t h2 = m_Predictables[ j ];
  129. C_BaseEntity *p1 = cl_entitylist->GetBaseEntityFromHandle( h1 );
  130. C_BaseEntity *p2 = cl_entitylist->GetBaseEntityFromHandle( h2 );
  131. if ( !p1 || !p2 )
  132. {
  133. Assert( 0 );
  134. continue;
  135. }
  136. if ( p1->entindex() != -1 &&
  137. p2->entindex() != -1 )
  138. {
  139. if ( p1->entindex() < p2->entindex() )
  140. continue;
  141. }
  142. if ( p2->entindex() == -1 )
  143. continue;
  144. m_Predictables[ i ] = h2;
  145. m_Predictables[ j ] = h1;
  146. }
  147. }
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose:
  151. // Input : remove -
  152. //-----------------------------------------------------------------------------
  153. void CPredictableList::RemoveFromPredictablesList( ClientEntityHandle_t remove )
  154. {
  155. m_Predictables.FindAndRemove( remove );
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose:
  159. // Input : slot -
  160. // Output : C_BaseEntity
  161. //-----------------------------------------------------------------------------
  162. C_BaseEntity *CPredictableList::GetPredictable( int slot )
  163. {
  164. return cl_entitylist->GetBaseEntityFromHandle( m_Predictables[ slot ] );
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Purpose:
  168. // Output : int
  169. //-----------------------------------------------------------------------------
  170. int CPredictableList::GetPredictableCount( void )
  171. {
  172. return m_Predictables.Count();
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose: Searc predictables for previously created entity (by testId)
  176. // Input : testId -
  177. // Output : static C_BaseEntity
  178. //-----------------------------------------------------------------------------
  179. static C_BaseEntity *FindPreviouslyCreatedEntity( CPredictableId& testId )
  180. {
  181. int c = predictables->GetPredictableCount();
  182. int i;
  183. for ( i = 0; i < c; i++ )
  184. {
  185. C_BaseEntity *e = predictables->GetPredictable( i );
  186. if ( !e || !e->IsClientCreated() )
  187. continue;
  188. // Found it, note use of operator ==
  189. if ( testId == e->m_PredictableID )
  190. {
  191. return e;
  192. }
  193. }
  194. return NULL;
  195. }
  196. #endif
  197. abstract_class IRecordingList
  198. {
  199. public:
  200. virtual ~IRecordingList() {};
  201. virtual void AddToList( ClientEntityHandle_t add ) = 0;
  202. virtual void RemoveFromList( ClientEntityHandle_t remove ) = 0;
  203. virtual int Count() = 0;
  204. virtual IClientRenderable *Get( int index ) = 0;
  205. };
  206. class CRecordingList : public IRecordingList
  207. {
  208. public:
  209. virtual void AddToList( ClientEntityHandle_t add );
  210. virtual void RemoveFromList( ClientEntityHandle_t remove );
  211. virtual int Count();
  212. IClientRenderable *Get( int index );
  213. private:
  214. CUtlVector< ClientEntityHandle_t > m_Recording;
  215. };
  216. static CRecordingList g_RecordingList;
  217. IRecordingList *recordinglist = &g_RecordingList;
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Add entity to list
  220. // Input : add -
  221. // Output : int
  222. //-----------------------------------------------------------------------------
  223. void CRecordingList::AddToList( ClientEntityHandle_t add )
  224. {
  225. // This is a hack to remap slot to index
  226. if ( m_Recording.Find( add ) != m_Recording.InvalidIndex() )
  227. {
  228. return;
  229. }
  230. // Add to general list
  231. m_Recording.AddToTail( add );
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose:
  235. // Input : remove -
  236. //-----------------------------------------------------------------------------
  237. void CRecordingList::RemoveFromList( ClientEntityHandle_t remove )
  238. {
  239. m_Recording.FindAndRemove( remove );
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose:
  243. // Input : slot -
  244. // Output : IClientRenderable
  245. //-----------------------------------------------------------------------------
  246. IClientRenderable *CRecordingList::Get( int index )
  247. {
  248. return cl_entitylist->GetClientRenderableFromHandle( m_Recording[ index ] );
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose:
  252. // Output : int
  253. //-----------------------------------------------------------------------------
  254. int CRecordingList::Count()
  255. {
  256. return m_Recording.Count();
  257. }
  258. // Should these be somewhere else?
  259. #define PITCH 0
  260. //-----------------------------------------------------------------------------
  261. // Purpose: Decodes animtime and notes when it changes
  262. // Input : *pStruct - ( C_BaseEntity * ) used to flag animtime is changine
  263. // *pVarData -
  264. // *pIn -
  265. // objectID -
  266. //-----------------------------------------------------------------------------
  267. void RecvProxy_AnimTime( const CRecvProxyData *pData, void *pStruct, void *pOut )
  268. {
  269. C_BaseEntity *pEntity = ( C_BaseEntity * )pStruct;
  270. Assert( pOut == &pEntity->m_flAnimTime );
  271. int t;
  272. int tickbase;
  273. int addt;
  274. // Unpack the data.
  275. addt = pData->m_Value.m_Int;
  276. // Note, this needs to be encoded relative to packet timestamp, not raw client clock
  277. tickbase = gpGlobals->GetNetworkBase( gpGlobals->tickcount, pEntity->entindex() );
  278. t = tickbase;
  279. // and then go back to floating point time.
  280. t += addt; // Add in an additional up to 256 100ths from the server
  281. // center m_flAnimTime around current time.
  282. while (t < gpGlobals->tickcount - 127)
  283. t += 256;
  284. while (t > gpGlobals->tickcount + 127)
  285. t -= 256;
  286. pEntity->m_flAnimTime = ( t * TICK_INTERVAL );
  287. }
  288. void RecvProxy_SimulationTime( const CRecvProxyData *pData, void *pStruct, void *pOut )
  289. {
  290. C_BaseEntity *pEntity = ( C_BaseEntity * )pStruct;
  291. Assert( pOut == &pEntity->m_flSimulationTime );
  292. int t;
  293. int tickbase;
  294. int addt;
  295. // Unpack the data.
  296. addt = pData->m_Value.m_Int;
  297. // Note, this needs to be encoded relative to packet timestamp, not raw client clock
  298. tickbase = gpGlobals->GetNetworkBase( gpGlobals->tickcount, pEntity->entindex() );
  299. t = tickbase;
  300. // and then go back to floating point time.
  301. t += addt; // Add in an additional up to 256 100ths from the server
  302. // center m_flSimulationTime around current time.
  303. while (t < gpGlobals->tickcount - 127)
  304. t += 256;
  305. while (t > gpGlobals->tickcount + 127)
  306. t -= 256;
  307. pEntity->m_flSimulationTime = ( t * TICK_INTERVAL );
  308. }
  309. void RecvProxy_LocalVelocity( const CRecvProxyData *pData, void *pStruct, void *pOut )
  310. {
  311. CBaseEntity *pEnt = (CBaseEntity *)pStruct;
  312. Vector vecVelocity;
  313. vecVelocity.x = pData->m_Value.m_Vector[0];
  314. vecVelocity.y = pData->m_Value.m_Vector[1];
  315. vecVelocity.z = pData->m_Value.m_Vector[2];
  316. // SetLocalVelocity checks to see if the value has changed
  317. pEnt->SetLocalVelocity( vecVelocity );
  318. }
  319. void RecvProxy_ToolRecording( const CRecvProxyData *pData, void *pStruct, void *pOut )
  320. {
  321. if ( !ToolsEnabled() )
  322. return;
  323. CBaseEntity *pEnt = (CBaseEntity *)pStruct;
  324. pEnt->SetToolRecording( pData->m_Value.m_Int != 0 );
  325. }
  326. // Expose it to the engine.
  327. IMPLEMENT_CLIENTCLASS(C_BaseEntity, DT_BaseEntity, CBaseEntity);
  328. static void RecvProxy_MoveType( const CRecvProxyData *pData, void *pStruct, void *pOut )
  329. {
  330. ((C_BaseEntity*)pStruct)->SetMoveType( (MoveType_t)(pData->m_Value.m_Int) );
  331. }
  332. static void RecvProxy_MoveCollide( const CRecvProxyData *pData, void *pStruct, void *pOut )
  333. {
  334. ((C_BaseEntity*)pStruct)->SetMoveCollide( (MoveCollide_t)(pData->m_Value.m_Int) );
  335. }
  336. static void RecvProxy_Solid( const CRecvProxyData *pData, void *pStruct, void *pOut )
  337. {
  338. ((C_BaseEntity*)pStruct)->SetSolid( (SolidType_t)pData->m_Value.m_Int );
  339. }
  340. static void RecvProxy_SolidFlags( const CRecvProxyData *pData, void *pStruct, void *pOut )
  341. {
  342. ((C_BaseEntity*)pStruct)->SetSolidFlags( pData->m_Value.m_Int );
  343. }
  344. void RecvProxy_EffectFlags( const CRecvProxyData *pData, void *pStruct, void *pOut )
  345. {
  346. ((C_BaseEntity*)pStruct)->SetEffects( pData->m_Value.m_Int );
  347. }
  348. BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_AnimTimeMustBeFirst )
  349. RecvPropInt( RECVINFO(m_flAnimTime), 0, RecvProxy_AnimTime ),
  350. END_RECV_TABLE()
  351. #ifndef NO_ENTITY_PREDICTION
  352. BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_PredictableId )
  353. RecvPropPredictableId( RECVINFO( m_PredictableID ) ),
  354. RecvPropInt( RECVINFO( m_bIsPlayerSimulated ) ),
  355. END_RECV_TABLE()
  356. #endif
  357. BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity)
  358. RecvPropDataTable( "AnimTimeMustBeFirst", 0, 0, &REFERENCE_RECV_TABLE(DT_AnimTimeMustBeFirst) ),
  359. RecvPropInt( RECVINFO(m_flSimulationTime), 0, RecvProxy_SimulationTime ),
  360. RecvPropInt( RECVINFO( m_ubInterpolationFrame ) ),
  361. RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
  362. #if PREDICTION_ERROR_CHECK_LEVEL > 1
  363. RecvPropVector( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ),
  364. #else
  365. RecvPropQAngles( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ),
  366. #endif
  367. #ifdef DEMO_BACKWARDCOMPATABILITY
  368. RecvPropInt( RECVINFO(m_nModelIndex), 0, RecvProxy_IntToModelIndex16_BackCompatible ),
  369. #else
  370. RecvPropInt( RECVINFO(m_nModelIndex) ),
  371. #endif
  372. RecvPropInt(RECVINFO(m_fEffects), 0, RecvProxy_EffectFlags ),
  373. RecvPropInt(RECVINFO(m_nRenderMode)),
  374. RecvPropInt(RECVINFO(m_nRenderFX)),
  375. RecvPropInt(RECVINFO(m_clrRender)),
  376. RecvPropInt(RECVINFO(m_iTeamNum)),
  377. RecvPropInt(RECVINFO(m_CollisionGroup)),
  378. RecvPropFloat(RECVINFO(m_flElasticity)),
  379. RecvPropFloat(RECVINFO(m_flShadowCastDistance)),
  380. RecvPropEHandle( RECVINFO(m_hOwnerEntity) ),
  381. RecvPropEHandle( RECVINFO(m_hEffectEntity) ),
  382. RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ),
  383. RecvPropInt( RECVINFO( m_iParentAttachment ) ),
  384. RecvPropInt( "movetype", 0, SIZEOF_IGNORE, 0, RecvProxy_MoveType ),
  385. RecvPropInt( "movecollide", 0, SIZEOF_IGNORE, 0, RecvProxy_MoveCollide ),
  386. RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
  387. RecvPropInt( RECVINFO ( m_iTextureFrameIndex ) ),
  388. #if !defined( NO_ENTITY_PREDICTION )
  389. RecvPropDataTable( "predictable_id", 0, 0, &REFERENCE_RECV_TABLE( DT_PredictableId ) ),
  390. #endif
  391. RecvPropInt ( RECVINFO( m_bSimulatedEveryTick ), 0, RecvProxy_InterpolationAmountChanged ),
  392. RecvPropInt ( RECVINFO( m_bAnimatedEveryTick ), 0, RecvProxy_InterpolationAmountChanged ),
  393. RecvPropBool ( RECVINFO( m_bAlternateSorting ) ),
  394. #ifdef TF_CLIENT_DLL
  395. RecvPropArray3( RECVINFO_ARRAY(m_nModelIndexOverrides), RecvPropInt( RECVINFO(m_nModelIndexOverrides[0]) ) ),
  396. #endif
  397. END_RECV_TABLE()
  398. const float coordTolerance = 2.0f / (float)( 1 << COORD_FRACTIONAL_BITS );
  399. BEGIN_PREDICTION_DATA_NO_BASE( C_BaseEntity )
  400. // These have a special proxy to handle send/receive
  401. DEFINE_PRED_TYPEDESCRIPTION( m_Collision, CCollisionProperty ),
  402. DEFINE_PRED_FIELD( m_MoveType, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
  403. DEFINE_PRED_FIELD( m_MoveCollide, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
  404. DEFINE_FIELD( m_vecAbsVelocity, FIELD_VECTOR ),
  405. DEFINE_PRED_FIELD_TOL( m_vecVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.5f ),
  406. // DEFINE_PRED_FIELD( m_fEffects, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  407. DEFINE_PRED_FIELD( m_nRenderMode, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
  408. DEFINE_PRED_FIELD( m_nRenderFX, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
  409. // DEFINE_PRED_FIELD( m_flAnimTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  410. // DEFINE_PRED_FIELD( m_flSimulationTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  411. DEFINE_PRED_FIELD( m_fFlags, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  412. DEFINE_PRED_FIELD_TOL( m_vecViewOffset, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.25f ),
  413. DEFINE_PRED_FIELD( m_nModelIndex, FIELD_SHORT, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
  414. DEFINE_PRED_FIELD( m_flFriction, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  415. DEFINE_PRED_FIELD( m_iTeamNum, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  416. DEFINE_PRED_FIELD( m_hOwnerEntity, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  417. // DEFINE_FIELD( m_nSimulationTick, FIELD_INTEGER ),
  418. DEFINE_PRED_FIELD( m_hNetworkMoveParent, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  419. // DEFINE_PRED_FIELD( m_pMoveParent, FIELD_EHANDLE ),
  420. // DEFINE_PRED_FIELD( m_pMoveChild, FIELD_EHANDLE ),
  421. // DEFINE_PRED_FIELD( m_pMovePeer, FIELD_EHANDLE ),
  422. // DEFINE_PRED_FIELD( m_pMovePrevPeer, FIELD_EHANDLE ),
  423. DEFINE_PRED_FIELD_TOL( m_vecNetworkOrigin, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, coordTolerance ),
  424. DEFINE_PRED_FIELD( m_angNetworkAngles, FIELD_VECTOR, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ),
  425. DEFINE_FIELD( m_vecAbsOrigin, FIELD_VECTOR ),
  426. DEFINE_FIELD( m_angAbsRotation, FIELD_VECTOR ),
  427. DEFINE_FIELD( m_vecOrigin, FIELD_VECTOR ),
  428. DEFINE_FIELD( m_angRotation, FIELD_VECTOR ),
  429. // DEFINE_FIELD( m_hGroundEntity, FIELD_EHANDLE ),
  430. DEFINE_FIELD( m_nWaterLevel, FIELD_CHARACTER ),
  431. DEFINE_FIELD( m_nWaterType, FIELD_CHARACTER ),
  432. DEFINE_FIELD( m_vecAngVelocity, FIELD_VECTOR ),
  433. // DEFINE_FIELD( m_vecAbsAngVelocity, FIELD_VECTOR ),
  434. // DEFINE_FIELD( model, FIELD_INTEGER ), // writing pointer literally
  435. // DEFINE_FIELD( index, FIELD_INTEGER ),
  436. // DEFINE_FIELD( m_ClientHandle, FIELD_SHORT ),
  437. // DEFINE_FIELD( m_Partition, FIELD_SHORT ),
  438. // DEFINE_FIELD( m_hRender, FIELD_SHORT ),
  439. DEFINE_FIELD( m_bDormant, FIELD_BOOLEAN ),
  440. // DEFINE_FIELD( current_position, FIELD_INTEGER ),
  441. // DEFINE_FIELD( m_flLastMessageTime, FIELD_FLOAT ),
  442. DEFINE_FIELD( m_vecBaseVelocity, FIELD_VECTOR ),
  443. DEFINE_FIELD( m_iEFlags, FIELD_INTEGER ),
  444. DEFINE_FIELD( m_flGravity, FIELD_FLOAT ),
  445. // DEFINE_FIELD( m_ModelInstance, FIELD_SHORT ),
  446. DEFINE_FIELD( m_flProxyRandomValue, FIELD_FLOAT ),
  447. // DEFINE_FIELD( m_PredictableID, FIELD_INTEGER ),
  448. // DEFINE_FIELD( m_pPredictionContext, FIELD_POINTER ),
  449. // Stuff specific to rendering and therefore not to be copied back and forth
  450. // DEFINE_PRED_FIELD( m_clrRender, color32, FTYPEDESC_INSENDTABLE ),
  451. // DEFINE_FIELD( m_bReadyToDraw, FIELD_BOOLEAN ),
  452. // DEFINE_FIELD( anim, CLatchedAnim ),
  453. // DEFINE_FIELD( mouth, CMouthInfo ),
  454. // DEFINE_FIELD( GetAbsOrigin(), FIELD_VECTOR ),
  455. // DEFINE_FIELD( GetAbsAngles(), FIELD_VECTOR ),
  456. // DEFINE_FIELD( m_nNumAttachments, FIELD_SHORT ),
  457. // DEFINE_FIELD( m_pAttachmentAngles, FIELD_VECTOR ),
  458. // DEFINE_FIELD( m_pAttachmentOrigin, FIELD_VECTOR ),
  459. // DEFINE_FIELD( m_listentry, CSerialEntity ),
  460. // DEFINE_FIELD( m_ShadowHandle, ClientShadowHandle_t ),
  461. // DEFINE_FIELD( m_hThink, ClientThinkHandle_t ),
  462. // Definitely private and not copied around
  463. // DEFINE_FIELD( m_bPredictable, FIELD_BOOLEAN ),
  464. // DEFINE_FIELD( m_CollisionGroup, FIELD_INTEGER ),
  465. // DEFINE_FIELD( m_DataChangeEventRef, FIELD_INTEGER ),
  466. #if !defined( CLIENT_DLL )
  467. // DEFINE_FIELD( m_bPredictionEligible, FIELD_BOOLEAN ),
  468. #endif
  469. END_PREDICTION_DATA()
  470. //-----------------------------------------------------------------------------
  471. // Helper functions.
  472. //-----------------------------------------------------------------------------
  473. void SpewInterpolatedVar( CInterpolatedVar< Vector > *pVar )
  474. {
  475. Msg( "--------------------------------------------------\n" );
  476. int i = pVar->GetHead();
  477. CApparentVelocity<Vector> apparent;
  478. float prevtime = 0.0f;
  479. while ( 1 )
  480. {
  481. float changetime;
  482. Vector *pVal = pVar->GetHistoryValue( i, changetime );
  483. if ( !pVal )
  484. break;
  485. float vel = apparent.AddSample( changetime, *pVal );
  486. Msg( "%6.6f: (%.2f %.2f %.2f), vel: %.2f [dt %.1f]\n", changetime, VectorExpand( *pVal ), vel, prevtime == 0.0f ? 0.0f : 1000.0f * ( changetime - prevtime ) );
  487. i = pVar->GetNext( i );
  488. prevtime = changetime;
  489. }
  490. Msg( "--------------------------------------------------\n" );
  491. }
  492. void SpewInterpolatedVar( CInterpolatedVar< Vector > *pVar, float flNow, float flInterpAmount, bool bSpewAllEntries = true )
  493. {
  494. float target = flNow - flInterpAmount;
  495. Msg( "--------------------------------------------------\n" );
  496. int i = pVar->GetHead();
  497. CApparentVelocity<Vector> apparent;
  498. float newtime = 999999.0f;
  499. Vector newVec( 0, 0, 0 );
  500. bool bSpew = true;
  501. while ( 1 )
  502. {
  503. float changetime;
  504. Vector *pVal = pVar->GetHistoryValue( i, changetime );
  505. if ( !pVal )
  506. break;
  507. if ( bSpew && target >= changetime )
  508. {
  509. Vector o;
  510. pVar->DebugInterpolate( &o, flNow );
  511. bool bInterp = newtime != 999999.0f;
  512. float frac = 0.0f;
  513. char desc[ 32 ];
  514. if ( bInterp )
  515. {
  516. frac = ( target - changetime ) / ( newtime - changetime );
  517. Q_snprintf( desc, sizeof( desc ), "interpolated [%.2f]", frac );
  518. }
  519. else
  520. {
  521. bSpew = true;
  522. int savei = i;
  523. i = pVar->GetNext( i );
  524. float oldtertime = 0.0f;
  525. pVar->GetHistoryValue( i, oldtertime );
  526. if ( changetime != oldtertime )
  527. {
  528. frac = ( target - changetime ) / ( changetime - oldtertime );
  529. }
  530. Q_snprintf( desc, sizeof( desc ), "extrapolated [%.2f]", frac );
  531. i = savei;
  532. }
  533. if ( bSpew )
  534. {
  535. Msg( " > %6.6f: (%.2f %.2f %.2f) %s for %.1f msec\n",
  536. target,
  537. VectorExpand( o ),
  538. desc,
  539. 1000.0f * ( target - changetime ) );
  540. bSpew = false;
  541. }
  542. }
  543. float vel = apparent.AddSample( changetime, *pVal );
  544. if ( bSpewAllEntries )
  545. {
  546. Msg( " %6.6f: (%.2f %.2f %.2f), vel: %.2f [dt %.1f]\n", changetime, VectorExpand( *pVal ), vel, newtime == 999999.0f ? 0.0f : 1000.0f * ( newtime - changetime ) );
  547. }
  548. i = pVar->GetNext( i );
  549. newtime = changetime;
  550. newVec = *pVal;
  551. }
  552. Msg( "--------------------------------------------------\n" );
  553. }
  554. void SpewInterpolatedVar( CInterpolatedVar< float > *pVar )
  555. {
  556. Msg( "--------------------------------------------------\n" );
  557. int i = pVar->GetHead();
  558. CApparentVelocity<float> apparent;
  559. while ( 1 )
  560. {
  561. float changetime;
  562. float *pVal = pVar->GetHistoryValue( i, changetime );
  563. if ( !pVal )
  564. break;
  565. float vel = apparent.AddSample( changetime, *pVal );
  566. Msg( "%6.6f: (%.2f), vel: %.2f\n", changetime, *pVal, vel );
  567. i = pVar->GetNext( i );
  568. }
  569. Msg( "--------------------------------------------------\n" );
  570. }
  571. template<class T>
  572. void GetInterpolatedVarTimeRange( CInterpolatedVar<T> *pVar, float &flMin, float &flMax )
  573. {
  574. flMin = 1e23;
  575. flMax = -1e23;
  576. int i = pVar->GetHead();
  577. CApparentVelocity<Vector> apparent;
  578. while ( 1 )
  579. {
  580. float changetime;
  581. if ( !pVar->GetHistoryValue( i, changetime ) )
  582. return;
  583. flMin = MIN( flMin, changetime );
  584. flMax = MAX( flMax, changetime );
  585. i = pVar->GetNext( i );
  586. }
  587. }
  588. //-----------------------------------------------------------------------------
  589. // Global methods related to when abs data is correct
  590. //-----------------------------------------------------------------------------
  591. void C_BaseEntity::SetAbsQueriesValid( bool bValid )
  592. {
  593. // @MULTICORE: Always allow in worker threads, assume higher level code is handling correctly
  594. if ( !ThreadInMainThread() )
  595. return;
  596. if ( !bValid )
  597. {
  598. s_bAbsQueriesValid = false;
  599. }
  600. else
  601. {
  602. s_bAbsQueriesValid = true;
  603. }
  604. }
  605. bool C_BaseEntity::IsAbsQueriesValid( void )
  606. {
  607. if ( !ThreadInMainThread() )
  608. return true;
  609. return s_bAbsQueriesValid;
  610. }
  611. void C_BaseEntity::PushEnableAbsRecomputations( bool bEnable )
  612. {
  613. if ( !ThreadInMainThread() )
  614. return;
  615. if ( g_iAbsRecomputationStackPos < ARRAYSIZE( g_bAbsRecomputationStack ) )
  616. {
  617. g_bAbsRecomputationStack[g_iAbsRecomputationStackPos] = s_bAbsRecomputationEnabled;
  618. ++g_iAbsRecomputationStackPos;
  619. s_bAbsRecomputationEnabled = bEnable;
  620. }
  621. else
  622. {
  623. Assert( false );
  624. }
  625. }
  626. void C_BaseEntity::PopEnableAbsRecomputations()
  627. {
  628. if ( !ThreadInMainThread() )
  629. return;
  630. if ( g_iAbsRecomputationStackPos > 0 )
  631. {
  632. --g_iAbsRecomputationStackPos;
  633. s_bAbsRecomputationEnabled = g_bAbsRecomputationStack[g_iAbsRecomputationStackPos];
  634. }
  635. else
  636. {
  637. Assert( false );
  638. }
  639. }
  640. void C_BaseEntity::EnableAbsRecomputations( bool bEnable )
  641. {
  642. if ( !ThreadInMainThread() )
  643. return;
  644. // This should only be called at the frame level. Use PushEnableAbsRecomputations
  645. // if you're blocking out a section of code.
  646. Assert( g_iAbsRecomputationStackPos == 0 );
  647. s_bAbsRecomputationEnabled = bEnable;
  648. }
  649. bool C_BaseEntity::IsAbsRecomputationsEnabled()
  650. {
  651. if ( !ThreadInMainThread() )
  652. return true;
  653. return s_bAbsRecomputationEnabled;
  654. }
  655. int C_BaseEntity::GetTextureFrameIndex( void )
  656. {
  657. return m_iTextureFrameIndex;
  658. }
  659. void C_BaseEntity::SetTextureFrameIndex( int iIndex )
  660. {
  661. m_iTextureFrameIndex = iIndex;
  662. }
  663. //-----------------------------------------------------------------------------
  664. // Purpose:
  665. // Input : *map -
  666. //-----------------------------------------------------------------------------
  667. void C_BaseEntity::Interp_SetupMappings( VarMapping_t *map )
  668. {
  669. if( !map )
  670. return;
  671. int c = map->m_Entries.Count();
  672. for ( int i = 0; i < c; i++ )
  673. {
  674. VarMapEntry_t *e = &map->m_Entries[ i ];
  675. IInterpolatedVar *watcher = e->watcher;
  676. void *data = e->data;
  677. int type = e->type;
  678. watcher->Setup( data, type );
  679. watcher->SetInterpolationAmount( GetInterpolationAmount( watcher->GetType() ) );
  680. }
  681. }
  682. void C_BaseEntity::Interp_RestoreToLastNetworked( VarMapping_t *map )
  683. {
  684. VPROF( "C_BaseEntity::Interp_RestoreToLastNetworked" );
  685. PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, "restoretolastnetworked" );
  686. Vector oldOrigin = GetLocalOrigin();
  687. QAngle oldAngles = GetLocalAngles();
  688. Vector oldVel = GetLocalVelocity();
  689. int c = map->m_Entries.Count();
  690. for ( int i = 0; i < c; i++ )
  691. {
  692. VarMapEntry_t *e = &map->m_Entries[ i ];
  693. IInterpolatedVar *watcher = e->watcher;
  694. watcher->RestoreToLastNetworked();
  695. }
  696. BaseInterpolatePart2( oldOrigin, oldAngles, oldVel, 0 );
  697. }
  698. void C_BaseEntity::Interp_UpdateInterpolationAmounts( VarMapping_t *map )
  699. {
  700. if( !map )
  701. return;
  702. int c = map->m_Entries.Count();
  703. for ( int i = 0; i < c; i++ )
  704. {
  705. VarMapEntry_t *e = &map->m_Entries[ i ];
  706. IInterpolatedVar *watcher = e->watcher;
  707. watcher->SetInterpolationAmount( GetInterpolationAmount( watcher->GetType() ) );
  708. }
  709. }
  710. void C_BaseEntity::Interp_HierarchyUpdateInterpolationAmounts()
  711. {
  712. Interp_UpdateInterpolationAmounts( GetVarMapping() );
  713. for ( C_BaseEntity *pChild = FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
  714. {
  715. pChild->Interp_HierarchyUpdateInterpolationAmounts();
  716. }
  717. }
  718. inline int C_BaseEntity::Interp_Interpolate( VarMapping_t *map, float currentTime )
  719. {
  720. int bNoMoreChanges = 1;
  721. if ( currentTime < map->m_lastInterpolationTime )
  722. {
  723. for ( int i = 0; i < map->m_nInterpolatedEntries; i++ )
  724. {
  725. VarMapEntry_t *e = &map->m_Entries[ i ];
  726. e->m_bNeedsToInterpolate = true;
  727. }
  728. }
  729. map->m_lastInterpolationTime = currentTime;
  730. for ( int i = 0; i < map->m_nInterpolatedEntries; i++ )
  731. {
  732. VarMapEntry_t *e = &map->m_Entries[ i ];
  733. if ( !e->m_bNeedsToInterpolate )
  734. continue;
  735. IInterpolatedVar *watcher = e->watcher;
  736. Assert( !( watcher->GetType() & EXCLUDE_AUTO_INTERPOLATE ) );
  737. if ( watcher->Interpolate( currentTime ) )
  738. e->m_bNeedsToInterpolate = false;
  739. else
  740. bNoMoreChanges = 0;
  741. }
  742. return bNoMoreChanges;
  743. }
  744. //-----------------------------------------------------------------------------
  745. // Functions.
  746. //-----------------------------------------------------------------------------
  747. C_BaseEntity::C_BaseEntity() :
  748. m_iv_vecOrigin( "C_BaseEntity::m_iv_vecOrigin" ),
  749. m_iv_angRotation( "C_BaseEntity::m_iv_angRotation" ),
  750. m_iv_vecVelocity( "C_BaseEntity::m_iv_vecVelocity" )
  751. {
  752. AddVar( &m_vecOrigin, &m_iv_vecOrigin, LATCH_SIMULATION_VAR );
  753. AddVar( &m_angRotation, &m_iv_angRotation, LATCH_SIMULATION_VAR );
  754. // Removing this until we figure out why velocity introduces view hitching.
  755. // One possible fix is removing the player->ResetLatched() call in CGameMovement::FinishDuck(),
  756. // but that re-introduces a third-person hitching bug. One possible cause is the abrupt change
  757. // in player size/position that occurs when ducking, and how prediction tries to work through that.
  758. //
  759. // AddVar( &m_vecVelocity, &m_iv_vecVelocity, LATCH_SIMULATION_VAR );
  760. m_DataChangeEventRef = -1;
  761. m_EntClientFlags = 0;
  762. m_iParentAttachment = 0;
  763. m_nRenderFXBlend = 255;
  764. SetPredictionEligible( false );
  765. m_bPredictable = false;
  766. m_bSimulatedEveryTick = false;
  767. m_bAnimatedEveryTick = false;
  768. m_pPhysicsObject = NULL;
  769. #ifdef _DEBUG
  770. m_vecAbsOrigin = vec3_origin;
  771. m_angAbsRotation = vec3_angle;
  772. m_vecNetworkOrigin.Init();
  773. m_angNetworkAngles.Init();
  774. m_vecAbsOrigin.Init();
  775. // m_vecAbsAngVelocity.Init();
  776. m_vecVelocity.Init();
  777. m_vecAbsVelocity.Init();
  778. m_vecViewOffset.Init();
  779. m_vecBaseVelocity.Init();
  780. m_iCurrentThinkContext = NO_THINK_CONTEXT;
  781. #endif
  782. m_nSimulationTick = -1;
  783. // Assume drawing everything
  784. m_bReadyToDraw = true;
  785. m_flProxyRandomValue = 0.0f;
  786. m_fBBoxVisFlags = 0;
  787. #if !defined( NO_ENTITY_PREDICTION )
  788. m_pPredictionContext = NULL;
  789. #endif
  790. //NOTE: not virtual! we are in the constructor!
  791. C_BaseEntity::Clear();
  792. m_InterpolationListEntry = 0xFFFF;
  793. m_TeleportListEntry = 0xFFFF;
  794. #ifndef NO_TOOLFRAMEWORK
  795. m_bEnabledInToolView = true;
  796. m_bToolRecording = false;
  797. m_ToolHandle = 0;
  798. m_nLastRecordedFrame = -1;
  799. m_bRecordInTools = true;
  800. #endif
  801. #ifdef TF_CLIENT_DLL
  802. m_bValidatedOwner = false;
  803. m_bDeemedInvalid = false;
  804. m_bWasDeemedInvalid = false;
  805. #endif
  806. ParticleProp()->Init( this );
  807. }
  808. //-----------------------------------------------------------------------------
  809. // Purpose:
  810. // Input :
  811. // Output :
  812. //-----------------------------------------------------------------------------
  813. C_BaseEntity::~C_BaseEntity()
  814. {
  815. Term();
  816. ClearDataChangedEvent( m_DataChangeEventRef );
  817. #if !defined( NO_ENTITY_PREDICTION )
  818. delete m_pPredictionContext;
  819. #endif
  820. RemoveFromInterpolationList();
  821. RemoveFromTeleportList();
  822. }
  823. void C_BaseEntity::Clear( void )
  824. {
  825. m_bDormant = true;
  826. m_nCreationTick = -1;
  827. m_RefEHandle.Term();
  828. m_ModelInstance = MODEL_INSTANCE_INVALID;
  829. m_ShadowHandle = CLIENTSHADOW_INVALID_HANDLE;
  830. m_hRender = INVALID_CLIENT_RENDER_HANDLE;
  831. m_hThink = INVALID_THINK_HANDLE;
  832. m_AimEntsListHandle = INVALID_AIMENTS_LIST_HANDLE;
  833. index = -1;
  834. m_Collision.Init( this );
  835. SetLocalOrigin( vec3_origin );
  836. SetLocalAngles( vec3_angle );
  837. model = NULL;
  838. m_vecAbsOrigin.Init();
  839. m_angAbsRotation.Init();
  840. m_vecVelocity.Init();
  841. ClearFlags();
  842. m_vecViewOffset.Init();
  843. m_vecBaseVelocity.Init();
  844. m_nModelIndex = 0;
  845. m_flAnimTime = 0;
  846. m_flSimulationTime = 0;
  847. SetSolid( SOLID_NONE );
  848. SetSolidFlags( 0 );
  849. SetMoveCollide( MOVECOLLIDE_DEFAULT );
  850. SetMoveType( MOVETYPE_NONE );
  851. ClearEffects();
  852. m_iEFlags = 0;
  853. m_nRenderMode = 0;
  854. m_nOldRenderMode = 0;
  855. SetRenderColor( 255, 255, 255, 255 );
  856. m_nRenderFX = 0;
  857. m_flFriction = 0.0f;
  858. m_flGravity = 0.0f;
  859. SetCheckUntouch( false );
  860. m_ShadowDirUseOtherEntity = NULL;
  861. m_nLastThinkTick = gpGlobals->tickcount;
  862. #if defined(SIXENSE)
  863. m_vecEyeOffset.Init();
  864. m_EyeAngleOffset.Init();
  865. #endif
  866. // Remove prediction context if it exists
  867. #if !defined( NO_ENTITY_PREDICTION )
  868. delete m_pPredictionContext;
  869. m_pPredictionContext = NULL;
  870. #endif
  871. // Do not enable this on all entities. It forces bone setup for entities that
  872. // don't need it.
  873. //AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  874. UpdateVisibility();
  875. }
  876. //-----------------------------------------------------------------------------
  877. // Purpose:
  878. //-----------------------------------------------------------------------------
  879. void C_BaseEntity::Spawn( void )
  880. {
  881. }
  882. //-----------------------------------------------------------------------------
  883. // Purpose:
  884. //-----------------------------------------------------------------------------
  885. void C_BaseEntity::Activate()
  886. {
  887. }
  888. //-----------------------------------------------------------------------------
  889. // Purpose:
  890. //-----------------------------------------------------------------------------
  891. void C_BaseEntity::SpawnClientEntity( void )
  892. {
  893. }
  894. //-----------------------------------------------------------------------------
  895. // Purpose:
  896. //-----------------------------------------------------------------------------
  897. void C_BaseEntity::Precache( void )
  898. {
  899. }
  900. //-----------------------------------------------------------------------------
  901. // Purpose: Attach to entity
  902. // Input : *pEnt -
  903. // Output : Returns true on success, false on failure.
  904. //-----------------------------------------------------------------------------
  905. bool C_BaseEntity::Init( int entnum, int iSerialNum )
  906. {
  907. Assert( entnum >= 0 && entnum < NUM_ENT_ENTRIES );
  908. index = entnum;
  909. cl_entitylist->AddNetworkableEntity( GetIClientUnknown(), entnum, iSerialNum );
  910. CollisionProp()->CreatePartitionHandle();
  911. Interp_SetupMappings( GetVarMapping() );
  912. m_nCreationTick = gpGlobals->tickcount;
  913. return true;
  914. }
  915. //-----------------------------------------------------------------------------
  916. // Purpose:
  917. //-----------------------------------------------------------------------------
  918. bool C_BaseEntity::InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup )
  919. {
  920. int nModelIndex;
  921. if ( pszModelName != NULL )
  922. {
  923. nModelIndex = modelinfo->GetModelIndex( pszModelName );
  924. if ( nModelIndex == -1 )
  925. {
  926. // Model could not be found
  927. Assert( !"Model could not be found, index is -1" );
  928. return false;
  929. }
  930. }
  931. else
  932. {
  933. nModelIndex = -1;
  934. }
  935. Interp_SetupMappings( GetVarMapping() );
  936. return InitializeAsClientEntityByIndex( nModelIndex, renderGroup );
  937. }
  938. //-----------------------------------------------------------------------------
  939. // Purpose:
  940. //-----------------------------------------------------------------------------
  941. bool C_BaseEntity::InitializeAsClientEntityByIndex( int iIndex, RenderGroup_t renderGroup )
  942. {
  943. index = -1;
  944. // Setup model data.
  945. SetModelByIndex( iIndex );
  946. // Add the client entity to the master entity list.
  947. cl_entitylist->AddNonNetworkableEntity( GetIClientUnknown() );
  948. Assert( GetClientHandle() != ClientEntityList().InvalidHandle() );
  949. // Add the client entity to the renderable "leaf system." (Renderable)
  950. AddToLeafSystem( renderGroup );
  951. // Add the client entity to the spatial partition. (Collidable)
  952. CollisionProp()->CreatePartitionHandle();
  953. SpawnClientEntity();
  954. return true;
  955. }
  956. void C_BaseEntity::Term()
  957. {
  958. C_BaseEntity::PhysicsRemoveTouchedList( this );
  959. C_BaseEntity::PhysicsRemoveGroundList( this );
  960. DestroyAllDataObjects();
  961. #if !defined( NO_ENTITY_PREDICTION )
  962. // Remove from the predictables list
  963. if ( GetPredictable() || IsClientCreated() )
  964. {
  965. g_Predictables.RemoveFromPredictablesList( GetClientHandle() );
  966. }
  967. // If it's play simulated, remove from simulation list if the player still exists...
  968. if ( IsPlayerSimulated() && C_BasePlayer::GetLocalPlayer() )
  969. {
  970. C_BasePlayer::GetLocalPlayer()->RemoveFromPlayerSimulationList( this );
  971. }
  972. #endif
  973. if ( GetClientHandle() != INVALID_CLIENTENTITY_HANDLE )
  974. {
  975. if ( GetThinkHandle() != INVALID_THINK_HANDLE )
  976. {
  977. ClientThinkList()->RemoveThinkable( GetClientHandle() );
  978. }
  979. // Remove from the client entity list.
  980. ClientEntityList().RemoveEntity( GetClientHandle() );
  981. m_RefEHandle = INVALID_CLIENTENTITY_HANDLE;
  982. }
  983. // Are we in the partition?
  984. CollisionProp()->DestroyPartitionHandle();
  985. // If Client side only entity index will be -1
  986. if ( index != -1 )
  987. {
  988. beams->KillDeadBeams( this );
  989. }
  990. // Clean up the model instance
  991. DestroyModelInstance();
  992. // Clean up drawing
  993. RemoveFromLeafSystem();
  994. RemoveFromAimEntsList();
  995. }
  996. void C_BaseEntity::SetRefEHandle( const CBaseHandle &handle )
  997. {
  998. m_RefEHandle = handle;
  999. }
  1000. const CBaseHandle& C_BaseEntity::GetRefEHandle() const
  1001. {
  1002. return m_RefEHandle;
  1003. }
  1004. //-----------------------------------------------------------------------------
  1005. // Purpose: Free beams and destroy object
  1006. //-----------------------------------------------------------------------------
  1007. void C_BaseEntity::Release()
  1008. {
  1009. {
  1010. C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true );
  1011. UnlinkFromHierarchy();
  1012. }
  1013. // Note that this must be called from here, not the destructor, because otherwise the
  1014. // vtable is hosed and the derived classes function is not going to get called!!!
  1015. if ( IsIntermediateDataAllocated() )
  1016. {
  1017. DestroyIntermediateData();
  1018. }
  1019. UpdateOnRemove();
  1020. delete this;
  1021. }
  1022. //-----------------------------------------------------------------------------
  1023. // Only meant to be called from subclasses.
  1024. // Returns true if instance valid, false otherwise
  1025. //-----------------------------------------------------------------------------
  1026. void C_BaseEntity::CreateModelInstance()
  1027. {
  1028. if ( m_ModelInstance == MODEL_INSTANCE_INVALID )
  1029. {
  1030. m_ModelInstance = modelrender->CreateInstance( this );
  1031. }
  1032. }
  1033. //-----------------------------------------------------------------------------
  1034. // Purpose:
  1035. //-----------------------------------------------------------------------------
  1036. void C_BaseEntity::DestroyModelInstance()
  1037. {
  1038. if (m_ModelInstance != MODEL_INSTANCE_INVALID)
  1039. {
  1040. modelrender->DestroyInstance( m_ModelInstance );
  1041. m_ModelInstance = MODEL_INSTANCE_INVALID;
  1042. }
  1043. }
  1044. void C_BaseEntity::SetRemovalFlag( bool bRemove )
  1045. {
  1046. if (bRemove)
  1047. m_iEFlags |= EFL_KILLME;
  1048. else
  1049. m_iEFlags &= ~EFL_KILLME;
  1050. }
  1051. //-----------------------------------------------------------------------------
  1052. // VPhysics objects..
  1053. //-----------------------------------------------------------------------------
  1054. int C_BaseEntity::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax )
  1055. {
  1056. IPhysicsObject *pPhys = VPhysicsGetObject();
  1057. if ( pPhys )
  1058. {
  1059. // multi-object entities must implement this function
  1060. Assert( !(pPhys->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) );
  1061. if ( listMax > 0 )
  1062. {
  1063. pList[0] = pPhys;
  1064. return 1;
  1065. }
  1066. }
  1067. return 0;
  1068. }
  1069. bool C_BaseEntity::VPhysicsIsFlesh( void )
  1070. {
  1071. IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
  1072. int count = VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
  1073. for ( int i = 0; i < count; i++ )
  1074. {
  1075. int material = pList[i]->GetMaterialIndex();
  1076. const surfacedata_t *pSurfaceData = physprops->GetSurfaceData( material );
  1077. // Is flesh ?, don't allow pickup
  1078. if ( pSurfaceData->game.material == CHAR_TEX_ANTLION || pSurfaceData->game.material == CHAR_TEX_FLESH || pSurfaceData->game.material == CHAR_TEX_BLOODYFLESH || pSurfaceData->game.material == CHAR_TEX_ALIENFLESH )
  1079. return true;
  1080. }
  1081. return false;
  1082. }
  1083. //-----------------------------------------------------------------------------
  1084. // Returns the health fraction
  1085. //-----------------------------------------------------------------------------
  1086. float C_BaseEntity::HealthFraction() const
  1087. {
  1088. if (GetMaxHealth() == 0)
  1089. return 1.0f;
  1090. float flFraction = (float)GetHealth() / (float)GetMaxHealth();
  1091. flFraction = clamp( flFraction, 0.0f, 1.0f );
  1092. return flFraction;
  1093. }
  1094. //-----------------------------------------------------------------------------
  1095. // Purpose: Retrieves the coordinate frame for this entity.
  1096. // Input : forward - Receives the entity's forward vector.
  1097. // right - Receives the entity's right vector.
  1098. // up - Receives the entity's up vector.
  1099. //-----------------------------------------------------------------------------
  1100. void C_BaseEntity::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const
  1101. {
  1102. // This call is necessary to cause m_rgflCoordinateFrame to be recomputed
  1103. const matrix3x4_t &entityToWorld = EntityToWorldTransform();
  1104. if (pForward != NULL)
  1105. {
  1106. MatrixGetColumn( entityToWorld, 0, *pForward );
  1107. }
  1108. if (pRight != NULL)
  1109. {
  1110. MatrixGetColumn( entityToWorld, 1, *pRight );
  1111. *pRight *= -1.0f;
  1112. }
  1113. if (pUp != NULL)
  1114. {
  1115. MatrixGetColumn( entityToWorld, 2, *pUp );
  1116. }
  1117. }
  1118. void C_BaseEntity::UpdateVisibility()
  1119. {
  1120. #ifdef TF_CLIENT_DLL
  1121. // TF prevents drawing of any entity attached to players that aren't items in the inventory of the player.
  1122. // This is to prevent servers creating fake cosmetic items and attaching them to players.
  1123. if ( !engine->IsPlayingDemo() )
  1124. {
  1125. static bool bIsStaging = ( engine->GetAppID() == 810 );
  1126. if ( !m_bValidatedOwner )
  1127. {
  1128. bool bRetry = false;
  1129. // Check it the first time we call update visibility (Source TV doesn't bother doing validation)
  1130. m_bDeemedInvalid = engine->IsHLTV() ? false : !ValidateEntityAttachedToPlayer( bRetry );
  1131. m_bValidatedOwner = !bRetry;
  1132. }
  1133. if ( m_bDeemedInvalid )
  1134. {
  1135. if ( bIsStaging )
  1136. {
  1137. if ( !m_bWasDeemedInvalid )
  1138. {
  1139. m_PreviousRenderMode = GetRenderMode();
  1140. m_PreviousRenderColor = GetRenderColor();
  1141. m_bWasDeemedInvalid = true;
  1142. }
  1143. SetRenderMode( kRenderTransColor );
  1144. SetRenderColor( 255, 0, 0, 200 );
  1145. }
  1146. else
  1147. {
  1148. RemoveFromLeafSystem();
  1149. return;
  1150. }
  1151. }
  1152. else if ( m_bWasDeemedInvalid )
  1153. {
  1154. if ( bIsStaging )
  1155. {
  1156. // We need to fix up the rendering.
  1157. SetRenderMode( m_PreviousRenderMode );
  1158. SetRenderColor( m_PreviousRenderColor.r, m_PreviousRenderColor.g, m_PreviousRenderColor.b, m_PreviousRenderColor.a );
  1159. }
  1160. m_bWasDeemedInvalid = false;
  1161. }
  1162. }
  1163. #endif
  1164. if ( ShouldDraw() && !IsDormant() && ( !ToolsEnabled() || IsEnabledInToolView() ) )
  1165. {
  1166. // add/update leafsystem
  1167. AddToLeafSystem();
  1168. }
  1169. else
  1170. {
  1171. // remove from leaf system
  1172. RemoveFromLeafSystem();
  1173. }
  1174. }
  1175. //-----------------------------------------------------------------------------
  1176. // Purpose: Returns whether object should render.
  1177. //-----------------------------------------------------------------------------
  1178. bool C_BaseEntity::ShouldDraw()
  1179. {
  1180. // Only test this in tf2
  1181. #if defined( INVASION_CLIENT_DLL )
  1182. // Let the client mode (like commander mode) reject drawing entities.
  1183. if (g_pClientMode && !g_pClientMode->ShouldDrawEntity(this) )
  1184. return false;
  1185. #endif
  1186. // Some rendermodes prevent rendering
  1187. if ( m_nRenderMode == kRenderNone )
  1188. return false;
  1189. return (model != 0) && !IsEffectActive(EF_NODRAW) && (index != 0);
  1190. }
  1191. bool C_BaseEntity::TestCollision( const Ray_t& ray, unsigned int mask, trace_t& trace )
  1192. {
  1193. return false;
  1194. }
  1195. bool C_BaseEntity::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  1196. {
  1197. return false;
  1198. }
  1199. //-----------------------------------------------------------------------------
  1200. // Used when the collision prop is told to ask game code for the world-space surrounding box
  1201. //-----------------------------------------------------------------------------
  1202. void C_BaseEntity::ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
  1203. {
  1204. // This should only be called if you're using USE_GAME_CODE on the server
  1205. // and you forgot to implement the client-side version of this method.
  1206. Assert(0);
  1207. }
  1208. //-----------------------------------------------------------------------------
  1209. // Purpose: Derived classes will have to write their own message cracking routines!!!
  1210. // Input : length -
  1211. // *data -
  1212. //-----------------------------------------------------------------------------
  1213. void C_BaseEntity::ReceiveMessage( int classID, bf_read &msg )
  1214. {
  1215. // BaseEntity doesn't have a base class we could relay this message to
  1216. Assert( classID == GetClientClass()->m_ClassID );
  1217. int messageType = msg.ReadByte();
  1218. switch( messageType )
  1219. {
  1220. case BASEENTITY_MSG_REMOVE_DECALS: RemoveAllDecals();
  1221. break;
  1222. }
  1223. }
  1224. void* C_BaseEntity::GetDataTableBasePtr()
  1225. {
  1226. return this;
  1227. }
  1228. //-----------------------------------------------------------------------------
  1229. // Should this object cast shadows?
  1230. //-----------------------------------------------------------------------------
  1231. ShadowType_t C_BaseEntity::ShadowCastType()
  1232. {
  1233. if (IsEffectActive(EF_NODRAW | EF_NOSHADOW))
  1234. return SHADOWS_NONE;
  1235. int modelType = modelinfo->GetModelType( model );
  1236. return (modelType == mod_studio) ? SHADOWS_RENDER_TO_TEXTURE : SHADOWS_NONE;
  1237. }
  1238. //-----------------------------------------------------------------------------
  1239. // Per-entity shadow cast distance + direction
  1240. //-----------------------------------------------------------------------------
  1241. bool C_BaseEntity::GetShadowCastDistance( float *pDistance, ShadowType_t shadowType ) const
  1242. {
  1243. if ( m_flShadowCastDistance != 0.0f )
  1244. {
  1245. *pDistance = m_flShadowCastDistance;
  1246. return true;
  1247. }
  1248. return false;
  1249. }
  1250. //-----------------------------------------------------------------------------
  1251. // Purpose:
  1252. //-----------------------------------------------------------------------------
  1253. C_BaseEntity *C_BaseEntity::GetShadowUseOtherEntity( void ) const
  1254. {
  1255. return m_ShadowDirUseOtherEntity;
  1256. }
  1257. //-----------------------------------------------------------------------------
  1258. // Purpose:
  1259. //-----------------------------------------------------------------------------
  1260. void C_BaseEntity::SetShadowUseOtherEntity( C_BaseEntity *pEntity )
  1261. {
  1262. m_ShadowDirUseOtherEntity = pEntity;
  1263. }
  1264. CInterpolatedVar< QAngle >& C_BaseEntity::GetRotationInterpolator()
  1265. {
  1266. return m_iv_angRotation;
  1267. }
  1268. CInterpolatedVar< Vector >& C_BaseEntity::GetOriginInterpolator()
  1269. {
  1270. return m_iv_vecOrigin;
  1271. }
  1272. //-----------------------------------------------------------------------------
  1273. // Purpose: Return a per-entity shadow cast direction
  1274. //-----------------------------------------------------------------------------
  1275. bool C_BaseEntity::GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const
  1276. {
  1277. if ( m_ShadowDirUseOtherEntity )
  1278. return m_ShadowDirUseOtherEntity->GetShadowCastDirection( pDirection, shadowType );
  1279. return false;
  1280. }
  1281. //-----------------------------------------------------------------------------
  1282. // Should this object receive shadows?
  1283. //-----------------------------------------------------------------------------
  1284. bool C_BaseEntity::ShouldReceiveProjectedTextures( int flags )
  1285. {
  1286. Assert( flags & SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK );
  1287. if ( IsEffectActive( EF_NODRAW ) )
  1288. return false;
  1289. if( flags & SHADOW_FLAGS_FLASHLIGHT )
  1290. {
  1291. if ( GetRenderMode() > kRenderNormal && GetRenderColor().a == 0 )
  1292. return false;
  1293. return true;
  1294. }
  1295. Assert( flags & SHADOW_FLAGS_SHADOW );
  1296. if ( IsEffectActive( EF_NORECEIVESHADOW ) )
  1297. return false;
  1298. if (modelinfo->GetModelType( model ) == mod_studio)
  1299. return false;
  1300. return true;
  1301. }
  1302. //-----------------------------------------------------------------------------
  1303. // Shadow-related methods
  1304. //-----------------------------------------------------------------------------
  1305. bool C_BaseEntity::IsShadowDirty( )
  1306. {
  1307. return IsEFlagSet( EFL_DIRTY_SHADOWUPDATE );
  1308. }
  1309. void C_BaseEntity::MarkShadowDirty( bool bDirty )
  1310. {
  1311. if ( bDirty )
  1312. {
  1313. AddEFlags( EFL_DIRTY_SHADOWUPDATE );
  1314. }
  1315. else
  1316. {
  1317. RemoveEFlags( EFL_DIRTY_SHADOWUPDATE );
  1318. }
  1319. }
  1320. IClientRenderable *C_BaseEntity::GetShadowParent()
  1321. {
  1322. C_BaseEntity *pParent = GetMoveParent();
  1323. return pParent ? pParent->GetClientRenderable() : NULL;
  1324. }
  1325. IClientRenderable *C_BaseEntity::FirstShadowChild()
  1326. {
  1327. C_BaseEntity *pChild = FirstMoveChild();
  1328. return pChild ? pChild->GetClientRenderable() : NULL;
  1329. }
  1330. IClientRenderable *C_BaseEntity::NextShadowPeer()
  1331. {
  1332. C_BaseEntity *pPeer = NextMovePeer();
  1333. return pPeer ? pPeer->GetClientRenderable() : NULL;
  1334. }
  1335. //-----------------------------------------------------------------------------
  1336. // Purpose: Returns index into entities list for this entity
  1337. // Output : Index
  1338. //-----------------------------------------------------------------------------
  1339. int C_BaseEntity::entindex( void ) const
  1340. {
  1341. return index;
  1342. }
  1343. int C_BaseEntity::GetSoundSourceIndex() const
  1344. {
  1345. #ifdef _DEBUG
  1346. if ( index != -1 )
  1347. {
  1348. Assert( index == GetRefEHandle().GetEntryIndex() );
  1349. }
  1350. #endif
  1351. return GetRefEHandle().GetEntryIndex();
  1352. }
  1353. //-----------------------------------------------------------------------------
  1354. // Get render origin and angles
  1355. //-----------------------------------------------------------------------------
  1356. const Vector& C_BaseEntity::GetRenderOrigin( void )
  1357. {
  1358. return GetAbsOrigin();
  1359. }
  1360. const QAngle& C_BaseEntity::GetRenderAngles( void )
  1361. {
  1362. return GetAbsAngles();
  1363. }
  1364. const matrix3x4_t &C_BaseEntity::RenderableToWorldTransform()
  1365. {
  1366. return EntityToWorldTransform();
  1367. }
  1368. IPVSNotify* C_BaseEntity::GetPVSNotifyInterface()
  1369. {
  1370. return NULL;
  1371. }
  1372. //-----------------------------------------------------------------------------
  1373. // Purpose:
  1374. // Input : theMins -
  1375. // theMaxs -
  1376. //-----------------------------------------------------------------------------
  1377. void C_BaseEntity::GetRenderBounds( Vector& theMins, Vector& theMaxs )
  1378. {
  1379. int nModelType = modelinfo->GetModelType( model );
  1380. if (nModelType == mod_studio || nModelType == mod_brush)
  1381. {
  1382. modelinfo->GetModelRenderBounds( GetModel(), theMins, theMaxs );
  1383. }
  1384. else
  1385. {
  1386. // By default, we'll just snack on the collision bounds, transform
  1387. // them into entity-space, and call it a day.
  1388. if ( GetRenderAngles() == CollisionProp()->GetCollisionAngles() )
  1389. {
  1390. theMins = CollisionProp()->OBBMins();
  1391. theMaxs = CollisionProp()->OBBMaxs();
  1392. }
  1393. else
  1394. {
  1395. Assert( CollisionProp()->GetCollisionAngles() == vec3_angle );
  1396. if ( IsPointSized() )
  1397. {
  1398. //theMins = CollisionProp()->GetCollisionOrigin();
  1399. //theMaxs = theMins;
  1400. theMins = theMaxs = vec3_origin;
  1401. }
  1402. else
  1403. {
  1404. // NOTE: This shouldn't happen! Or at least, I haven't run
  1405. // into a valid case where it should yet.
  1406. // Assert(0);
  1407. IRotateAABB( EntityToWorldTransform(), CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), theMins, theMaxs );
  1408. }
  1409. }
  1410. }
  1411. }
  1412. void C_BaseEntity::GetRenderBoundsWorldspace( Vector& mins, Vector& maxs )
  1413. {
  1414. DefaultRenderBoundsWorldspace( this, mins, maxs );
  1415. }
  1416. void C_BaseEntity::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType )
  1417. {
  1418. m_EntClientFlags |= ENTCLIENTFLAG_GETTINGSHADOWRENDERBOUNDS;
  1419. GetRenderBounds( mins, maxs );
  1420. m_EntClientFlags &= ~ENTCLIENTFLAG_GETTINGSHADOWRENDERBOUNDS;
  1421. }
  1422. //-----------------------------------------------------------------------------
  1423. // Purpose: Last received origin
  1424. // Output : const float
  1425. //-----------------------------------------------------------------------------
  1426. const Vector& C_BaseEntity::GetAbsOrigin( void ) const
  1427. {
  1428. //Assert( s_bAbsQueriesValid );
  1429. const_cast<C_BaseEntity*>(this)->CalcAbsolutePosition();
  1430. return m_vecAbsOrigin;
  1431. }
  1432. //-----------------------------------------------------------------------------
  1433. // Purpose: Last received angles
  1434. // Output : const
  1435. //-----------------------------------------------------------------------------
  1436. const QAngle& C_BaseEntity::GetAbsAngles( void ) const
  1437. {
  1438. //Assert( s_bAbsQueriesValid );
  1439. const_cast<C_BaseEntity*>(this)->CalcAbsolutePosition();
  1440. return m_angAbsRotation;
  1441. }
  1442. //-----------------------------------------------------------------------------
  1443. // Purpose:
  1444. // Input : org -
  1445. //-----------------------------------------------------------------------------
  1446. void C_BaseEntity::SetNetworkOrigin( const Vector& org )
  1447. {
  1448. m_vecNetworkOrigin = org;
  1449. }
  1450. //-----------------------------------------------------------------------------
  1451. // Purpose:
  1452. // Input : ang -
  1453. //-----------------------------------------------------------------------------
  1454. void C_BaseEntity::SetNetworkAngles( const QAngle& ang )
  1455. {
  1456. m_angNetworkAngles = ang;
  1457. }
  1458. //-----------------------------------------------------------------------------
  1459. // Purpose:
  1460. // Input : index -
  1461. //-----------------------------------------------------------------------------
  1462. void C_BaseEntity::SetModelIndex( int index )
  1463. {
  1464. m_nModelIndex = index;
  1465. const model_t *pModel = modelinfo->GetModel( m_nModelIndex );
  1466. SetModelPointer( pModel );
  1467. }
  1468. void C_BaseEntity::SetModelPointer( const model_t *pModel )
  1469. {
  1470. if ( pModel != model )
  1471. {
  1472. DestroyModelInstance();
  1473. model = pModel;
  1474. OnNewModel();
  1475. UpdateVisibility();
  1476. }
  1477. }
  1478. //-----------------------------------------------------------------------------
  1479. // Purpose:
  1480. // Input : val -
  1481. // moveCollide -
  1482. //-----------------------------------------------------------------------------
  1483. void C_BaseEntity::SetMoveType( MoveType_t val, MoveCollide_t moveCollide /*= MOVECOLLIDE_DEFAULT*/ )
  1484. {
  1485. // Make sure the move type + move collide are compatible...
  1486. #ifdef _DEBUG
  1487. if ((val != MOVETYPE_FLY) && (val != MOVETYPE_FLYGRAVITY))
  1488. {
  1489. Assert( moveCollide == MOVECOLLIDE_DEFAULT );
  1490. }
  1491. #endif
  1492. m_MoveType = val;
  1493. SetMoveCollide( moveCollide );
  1494. }
  1495. void C_BaseEntity::SetMoveCollide( MoveCollide_t val )
  1496. {
  1497. m_MoveCollide = val;
  1498. }
  1499. //-----------------------------------------------------------------------------
  1500. // Purpose: Get rendermode
  1501. // Output : int - the render mode
  1502. //-----------------------------------------------------------------------------
  1503. bool C_BaseEntity::IsTransparent( void )
  1504. {
  1505. bool modelIsTransparent = modelinfo->IsTranslucent(model);
  1506. return modelIsTransparent || (m_nRenderMode != kRenderNormal);
  1507. }
  1508. bool C_BaseEntity::IsTwoPass( void )
  1509. {
  1510. return modelinfo->IsTranslucentTwoPass( GetModel() );
  1511. }
  1512. bool C_BaseEntity::UsesPowerOfTwoFrameBufferTexture()
  1513. {
  1514. return false;
  1515. }
  1516. bool C_BaseEntity::UsesFullFrameBufferTexture()
  1517. {
  1518. return false;
  1519. }
  1520. bool C_BaseEntity::IgnoresZBuffer( void ) const
  1521. {
  1522. return m_nRenderMode == kRenderGlow || m_nRenderMode == kRenderWorldGlow;
  1523. }
  1524. //-----------------------------------------------------------------------------
  1525. // Purpose: Get pointer to CMouthInfo data
  1526. // Output : CMouthInfo
  1527. //-----------------------------------------------------------------------------
  1528. CMouthInfo *C_BaseEntity::GetMouth( void )
  1529. {
  1530. return NULL;
  1531. }
  1532. //-----------------------------------------------------------------------------
  1533. // Purpose: Retrieve sound spatialization info for the specified sound on this entity
  1534. // Input : info -
  1535. // Output : Return false to indicate sound is not audible
  1536. //-----------------------------------------------------------------------------
  1537. bool C_BaseEntity::GetSoundSpatialization( SpatializationInfo_t& info )
  1538. {
  1539. // World is always audible
  1540. if ( entindex() == 0 )
  1541. {
  1542. return true;
  1543. }
  1544. // Out of PVS
  1545. if ( IsDormant() )
  1546. {
  1547. return false;
  1548. }
  1549. // pModel might be NULL, but modelinfo can handle that
  1550. const model_t *pModel = GetModel();
  1551. if ( info.pflRadius )
  1552. {
  1553. *info.pflRadius = modelinfo->GetModelRadius( pModel );
  1554. }
  1555. if ( info.pOrigin )
  1556. {
  1557. *info.pOrigin = GetAbsOrigin();
  1558. // move origin to middle of brush
  1559. if ( modelinfo->GetModelType( pModel ) == mod_brush )
  1560. {
  1561. Vector mins, maxs, center;
  1562. modelinfo->GetModelBounds( pModel, mins, maxs );
  1563. VectorAdd( mins, maxs, center );
  1564. VectorScale( center, 0.5f, center );
  1565. (*info.pOrigin) += center;
  1566. }
  1567. }
  1568. if ( info.pAngles )
  1569. {
  1570. VectorCopy( GetAbsAngles(), *info.pAngles );
  1571. }
  1572. return true;
  1573. }
  1574. //-----------------------------------------------------------------------------
  1575. // Purpose: Get attachment point by index
  1576. // Input : number - which point
  1577. // Output : float * - the attachment point
  1578. //-----------------------------------------------------------------------------
  1579. bool C_BaseEntity::GetAttachment( int number, Vector &origin, QAngle &angles )
  1580. {
  1581. origin = GetAbsOrigin();
  1582. angles = GetAbsAngles();
  1583. return true;
  1584. }
  1585. bool C_BaseEntity::GetAttachment( int number, Vector &origin )
  1586. {
  1587. origin = GetAbsOrigin();
  1588. return true;
  1589. }
  1590. bool C_BaseEntity::GetAttachment( int number, matrix3x4_t &matrix )
  1591. {
  1592. MatrixCopy( EntityToWorldTransform(), matrix );
  1593. return true;
  1594. }
  1595. bool C_BaseEntity::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
  1596. {
  1597. originVel = GetAbsVelocity();
  1598. angleVel.Init();
  1599. return true;
  1600. }
  1601. //-----------------------------------------------------------------------------
  1602. // Purpose: Get this entity's rendering clip plane if one is defined
  1603. // Output : float * - The clip plane to use, or NULL if no clip plane is defined
  1604. //-----------------------------------------------------------------------------
  1605. float *C_BaseEntity::GetRenderClipPlane( void )
  1606. {
  1607. if( m_bEnableRenderingClipPlane )
  1608. return m_fRenderingClipPlane;
  1609. else
  1610. return NULL;
  1611. }
  1612. //-----------------------------------------------------------------------------
  1613. // Purpose:
  1614. //-----------------------------------------------------------------------------
  1615. int C_BaseEntity::DrawBrushModel( bool bDrawingTranslucency, int nFlags, bool bTwoPass )
  1616. {
  1617. VPROF_BUDGET( "C_BaseEntity::DrawBrushModel", VPROF_BUDGETGROUP_BRUSHMODEL_RENDERING );
  1618. // Identity brushes are drawn in view->DrawWorld as an optimization
  1619. Assert ( modelinfo->GetModelType( model ) == mod_brush );
  1620. ERenderDepthMode DepthMode = DEPTH_MODE_NORMAL;
  1621. if ( ( nFlags & STUDIO_SSAODEPTHTEXTURE ) != 0 )
  1622. {
  1623. DepthMode = DEPTH_MODE_SSA0;
  1624. }
  1625. else if ( ( nFlags & STUDIO_SHADOWDEPTHTEXTURE ) != 0 )
  1626. {
  1627. DepthMode = DEPTH_MODE_SHADOW;
  1628. }
  1629. if ( DepthMode != DEPTH_MODE_NORMAL )
  1630. {
  1631. render->DrawBrushModelShadowDepth( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), DepthMode );
  1632. }
  1633. else
  1634. {
  1635. DrawBrushModelMode_t mode = DBM_DRAW_ALL;
  1636. if ( bTwoPass )
  1637. {
  1638. mode = bDrawingTranslucency ? DBM_DRAW_TRANSLUCENT_ONLY : DBM_DRAW_OPAQUE_ONLY;
  1639. }
  1640. render->DrawBrushModelEx( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), mode );
  1641. }
  1642. return 1;
  1643. }
  1644. //-----------------------------------------------------------------------------
  1645. // Purpose: Draws the object
  1646. // Input : flags -
  1647. //-----------------------------------------------------------------------------
  1648. int C_BaseEntity::DrawModel( int flags )
  1649. {
  1650. if ( !m_bReadyToDraw )
  1651. return 0;
  1652. int drawn = 0;
  1653. if ( !model )
  1654. {
  1655. return drawn;
  1656. }
  1657. int modelType = modelinfo->GetModelType( model );
  1658. switch ( modelType )
  1659. {
  1660. case mod_brush:
  1661. drawn = DrawBrushModel( flags & STUDIO_TRANSPARENCY ? true : false, flags, ( flags & STUDIO_TWOPASS ) ? true : false );
  1662. break;
  1663. case mod_studio:
  1664. // All studio models must be derived from C_BaseAnimating. Issue warning.
  1665. Warning( "ERROR: Can't draw studio model %s because %s is not derived from C_BaseAnimating\n",
  1666. modelinfo->GetModelName( model ), GetClientClass()->m_pNetworkName ? GetClientClass()->m_pNetworkName : "unknown" );
  1667. break;
  1668. case mod_sprite:
  1669. //drawn = DrawSprite();
  1670. Warning( "ERROR: Sprite model's not supported any more except in legacy temp ents\n" );
  1671. break;
  1672. default:
  1673. break;
  1674. }
  1675. // If we're visualizing our bboxes, draw them
  1676. DrawBBoxVisualizations();
  1677. return drawn;
  1678. }
  1679. //-----------------------------------------------------------------------------
  1680. // Purpose: Setup the bones for drawing
  1681. //-----------------------------------------------------------------------------
  1682. bool C_BaseEntity::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  1683. {
  1684. return true;
  1685. }
  1686. //-----------------------------------------------------------------------------
  1687. // Purpose: Setup vertex weights for drawing
  1688. //-----------------------------------------------------------------------------
  1689. void C_BaseEntity::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
  1690. {
  1691. }
  1692. //-----------------------------------------------------------------------------
  1693. // Purpose: Process any local client-side animation events
  1694. //-----------------------------------------------------------------------------
  1695. void C_BaseEntity::DoAnimationEvents( )
  1696. {
  1697. }
  1698. void C_BaseEntity::UpdatePartitionListEntry()
  1699. {
  1700. // Don't add the world entity
  1701. CollideType_t shouldCollide = GetCollideType();
  1702. // Choose the list based on what kind of collisions we want
  1703. int list = PARTITION_CLIENT_NON_STATIC_EDICTS;
  1704. if (shouldCollide == ENTITY_SHOULD_COLLIDE)
  1705. list |= PARTITION_CLIENT_SOLID_EDICTS;
  1706. else if (shouldCollide == ENTITY_SHOULD_RESPOND)
  1707. list |= PARTITION_CLIENT_RESPONSIVE_EDICTS;
  1708. // add the entity to the KD tree so we will collide against it
  1709. partition->RemoveAndInsert( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, list, CollisionProp()->GetPartitionHandle() );
  1710. }
  1711. void C_BaseEntity::NotifyShouldTransmit( ShouldTransmitState_t state )
  1712. {
  1713. // Init should have been called before we get in here.
  1714. Assert( CollisionProp()->GetPartitionHandle() != PARTITION_INVALID_HANDLE );
  1715. if ( entindex() < 0 )
  1716. return;
  1717. switch( state )
  1718. {
  1719. case SHOULDTRANSMIT_START:
  1720. {
  1721. // We've just been sent by the server. Become active.
  1722. SetDormant( false );
  1723. UpdatePartitionListEntry();
  1724. #if !defined( NO_ENTITY_PREDICTION )
  1725. // Note that predictables get a chance to hook up to their server counterparts here
  1726. if ( m_PredictableID.IsActive() )
  1727. {
  1728. // Find corresponding client side predicted entity and remove it from predictables
  1729. m_PredictableID.SetAcknowledged( true );
  1730. C_BaseEntity *otherEntity = FindPreviouslyCreatedEntity( m_PredictableID );
  1731. if ( otherEntity )
  1732. {
  1733. Assert( otherEntity->IsClientCreated() );
  1734. Assert( otherEntity->m_PredictableID.IsActive() );
  1735. Assert( ClientEntityList().IsHandleValid( otherEntity->GetClientHandle() ) );
  1736. otherEntity->m_PredictableID.SetAcknowledged( true );
  1737. if ( OnPredictedEntityRemove( false, otherEntity ) )
  1738. {
  1739. // Mark it for delete after receive all network data
  1740. otherEntity->Release();
  1741. }
  1742. }
  1743. }
  1744. #endif
  1745. }
  1746. break;
  1747. case SHOULDTRANSMIT_END:
  1748. {
  1749. // Clear out links if we're out of the picture...
  1750. UnlinkFromHierarchy();
  1751. // We're no longer being sent by the server. Become dormant.
  1752. SetDormant( true );
  1753. // remove the entity from the KD tree so we won't collide against it
  1754. partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() );
  1755. }
  1756. break;
  1757. default:
  1758. Assert( 0 );
  1759. break;
  1760. }
  1761. }
  1762. //-----------------------------------------------------------------------------
  1763. // Call this in PostDataUpdate if you don't chain it down!
  1764. //-----------------------------------------------------------------------------
  1765. void C_BaseEntity::MarkMessageReceived()
  1766. {
  1767. m_flLastMessageTime = engine->GetLastTimeStamp();
  1768. }
  1769. //-----------------------------------------------------------------------------
  1770. // Purpose: Entity is about to be decoded from the network stream
  1771. // Input : bnewentity - is this a new entity this update?
  1772. //-----------------------------------------------------------------------------
  1773. void C_BaseEntity::PreDataUpdate( DataUpdateType_t updateType )
  1774. {
  1775. VPROF( "C_BaseEntity::PreDataUpdate" );
  1776. // Register for an OnDataChanged call and call OnPreDataChanged().
  1777. if ( AddDataChangeEvent( this, updateType, &m_DataChangeEventRef ) )
  1778. {
  1779. OnPreDataChanged( updateType );
  1780. }
  1781. // Need to spawn on client before receiving original network data
  1782. // in case it overrides any values set up in spawn ( e.g., m_iState )
  1783. bool bnewentity = (updateType == DATA_UPDATE_CREATED);
  1784. if ( !bnewentity )
  1785. {
  1786. Interp_RestoreToLastNetworked( GetVarMapping() );
  1787. }
  1788. if ( bnewentity && !IsClientCreated() )
  1789. {
  1790. m_flSpawnTime = engine->GetLastTimeStamp();
  1791. MDLCACHE_CRITICAL_SECTION();
  1792. Spawn();
  1793. }
  1794. #if 0 // Yahn suggesting commenting this out as a fix to demo recording not working
  1795. // If the entity moves itself every FRAME on the server but doesn't update animtime,
  1796. // then use the current server time as the time for interpolation.
  1797. if ( IsSelfAnimating() )
  1798. {
  1799. m_flAnimTime = engine->GetLastTimeStamp();
  1800. }
  1801. #endif
  1802. m_vecOldOrigin = GetNetworkOrigin();
  1803. m_vecOldAngRotation = GetNetworkAngles();
  1804. m_flOldAnimTime = m_flAnimTime;
  1805. m_flOldSimulationTime = m_flSimulationTime;
  1806. m_nOldRenderMode = m_nRenderMode;
  1807. if ( m_hRender != INVALID_CLIENT_RENDER_HANDLE )
  1808. {
  1809. ClientLeafSystem()->EnableAlternateSorting( m_hRender, m_bAlternateSorting );
  1810. }
  1811. m_ubOldInterpolationFrame = m_ubInterpolationFrame;
  1812. }
  1813. const Vector& C_BaseEntity::GetOldOrigin()
  1814. {
  1815. return m_vecOldOrigin;
  1816. }
  1817. void C_BaseEntity::UnlinkChild( C_BaseEntity *pParent, C_BaseEntity *pChild )
  1818. {
  1819. Assert( pChild );
  1820. Assert( pParent != pChild );
  1821. Assert( pChild->GetMoveParent() == pParent );
  1822. // Unlink from parent
  1823. // NOTE: pParent *may well be NULL*! This occurs
  1824. // when a child has unlinked from a parent, and the child
  1825. // remains in the PVS but the parent has not
  1826. if (pParent && (pParent->m_pMoveChild == pChild))
  1827. {
  1828. Assert( !(pChild->m_pMovePrevPeer.IsValid()) );
  1829. pParent->m_pMoveChild = pChild->m_pMovePeer;
  1830. }
  1831. // Unlink from siblings...
  1832. if (pChild->m_pMovePrevPeer)
  1833. {
  1834. pChild->m_pMovePrevPeer->m_pMovePeer = pChild->m_pMovePeer;
  1835. }
  1836. if (pChild->m_pMovePeer)
  1837. {
  1838. pChild->m_pMovePeer->m_pMovePrevPeer = pChild->m_pMovePrevPeer;
  1839. }
  1840. pChild->m_pMovePeer = NULL;
  1841. pChild->m_pMovePrevPeer = NULL;
  1842. pChild->m_pMoveParent = NULL;
  1843. pChild->RemoveFromAimEntsList();
  1844. Interp_HierarchyUpdateInterpolationAmounts();
  1845. }
  1846. void C_BaseEntity::LinkChild( C_BaseEntity *pParent, C_BaseEntity *pChild )
  1847. {
  1848. Assert( !pChild->m_pMovePeer.IsValid() );
  1849. Assert( !pChild->m_pMovePrevPeer.IsValid() );
  1850. Assert( !pChild->m_pMoveParent.IsValid() );
  1851. Assert( pParent != pChild );
  1852. #ifdef _DEBUG
  1853. // Make sure the child isn't already in this list
  1854. C_BaseEntity *pExistingChild;
  1855. for ( pExistingChild = pParent->FirstMoveChild(); pExistingChild; pExistingChild = pExistingChild->NextMovePeer() )
  1856. {
  1857. Assert( pChild != pExistingChild );
  1858. }
  1859. #endif
  1860. pChild->m_pMovePrevPeer = NULL;
  1861. pChild->m_pMovePeer = pParent->m_pMoveChild;
  1862. if (pChild->m_pMovePeer)
  1863. {
  1864. pChild->m_pMovePeer->m_pMovePrevPeer = pChild;
  1865. }
  1866. pParent->m_pMoveChild = pChild;
  1867. pChild->m_pMoveParent = pParent;
  1868. pChild->AddToAimEntsList();
  1869. Interp_HierarchyUpdateInterpolationAmounts();
  1870. }
  1871. CUtlVector< C_BaseEntity * > g_AimEntsList;
  1872. //-----------------------------------------------------------------------------
  1873. // Moves all aiments
  1874. //-----------------------------------------------------------------------------
  1875. void C_BaseEntity::MarkAimEntsDirty()
  1876. {
  1877. // FIXME: With the dirty bits hooked into cycle + sequence, it's unclear
  1878. // that this is even necessary any more (provided aiments are always accessing
  1879. // joints or attachments of the move parent).
  1880. //
  1881. // NOTE: This is a tricky algorithm. This list does not actually contain
  1882. // all aim-ents in its list. It actually contains all hierarchical children,
  1883. // of which aim-ents are a part. We can tell if something is an aiment if it has
  1884. // the EF_BONEMERGE effect flag set.
  1885. //
  1886. // We will first iterate over all aiments and clear their DIRTY_ABSTRANSFORM flag,
  1887. // which is necessary to cause them to recompute their aim-ent origin
  1888. // the next time CalcAbsPosition is called. Because CalcAbsPosition calls MoveToAimEnt
  1889. // and MoveToAimEnt calls SetAbsOrigin/SetAbsAngles, that is how CalcAbsPosition
  1890. // will cause the aim-ent's (and all its children's) dirty state to be correctly updated.
  1891. //
  1892. // Then we will iterate over the loop a second time and call CalcAbsPosition on them,
  1893. int i;
  1894. int c = g_AimEntsList.Count();
  1895. for ( i = 0; i < c; ++i )
  1896. {
  1897. C_BaseEntity *pEnt = g_AimEntsList[ i ];
  1898. Assert( pEnt && pEnt->GetMoveParent() );
  1899. if ( pEnt->IsEffectActive(EF_BONEMERGE | EF_PARENT_ANIMATES) )
  1900. {
  1901. pEnt->AddEFlags( EFL_DIRTY_ABSTRANSFORM );
  1902. }
  1903. }
  1904. }
  1905. void C_BaseEntity::CalcAimEntPositions()
  1906. {
  1907. VPROF("CalcAimEntPositions");
  1908. int i;
  1909. int c = g_AimEntsList.Count();
  1910. for ( i = 0; i < c; ++i )
  1911. {
  1912. C_BaseEntity *pEnt = g_AimEntsList[ i ];
  1913. Assert( pEnt );
  1914. Assert( pEnt->GetMoveParent() );
  1915. if ( pEnt->IsEffectActive(EF_BONEMERGE) )
  1916. {
  1917. pEnt->CalcAbsolutePosition( );
  1918. }
  1919. }
  1920. }
  1921. void C_BaseEntity::AddToAimEntsList()
  1922. {
  1923. // Already in list
  1924. if ( m_AimEntsListHandle != INVALID_AIMENTS_LIST_HANDLE )
  1925. return;
  1926. m_AimEntsListHandle = g_AimEntsList.AddToTail( this );
  1927. }
  1928. void C_BaseEntity::RemoveFromAimEntsList()
  1929. {
  1930. // Not in list yet
  1931. if ( INVALID_AIMENTS_LIST_HANDLE == m_AimEntsListHandle )
  1932. {
  1933. return;
  1934. }
  1935. unsigned int c = g_AimEntsList.Count();
  1936. Assert( m_AimEntsListHandle < c );
  1937. unsigned int last = c - 1;
  1938. if ( last == m_AimEntsListHandle )
  1939. {
  1940. // Just wipe the final entry
  1941. g_AimEntsList.FastRemove( last );
  1942. }
  1943. else
  1944. {
  1945. C_BaseEntity *lastEntity = g_AimEntsList[ last ];
  1946. // Remove the last entry
  1947. g_AimEntsList.FastRemove( last );
  1948. // And update it's handle to point to this slot.
  1949. lastEntity->m_AimEntsListHandle = m_AimEntsListHandle;
  1950. g_AimEntsList[ m_AimEntsListHandle ] = lastEntity;
  1951. }
  1952. // Invalidate our handle no matter what.
  1953. m_AimEntsListHandle = INVALID_AIMENTS_LIST_HANDLE;
  1954. }
  1955. //-----------------------------------------------------------------------------
  1956. // Update move-parent if needed. For SourceTV.
  1957. //-----------------------------------------------------------------------------
  1958. void C_BaseEntity::HierarchyUpdateMoveParent()
  1959. {
  1960. if ( m_hNetworkMoveParent.ToInt() == m_pMoveParent.ToInt() )
  1961. return;
  1962. HierarchySetParent( m_hNetworkMoveParent );
  1963. }
  1964. //-----------------------------------------------------------------------------
  1965. // Connects us up to hierarchy
  1966. //-----------------------------------------------------------------------------
  1967. void C_BaseEntity::HierarchySetParent( C_BaseEntity *pNewParent )
  1968. {
  1969. // NOTE: When this is called, we expect to have a valid
  1970. // local origin, etc. that we received from network daa
  1971. EHANDLE newParentHandle;
  1972. newParentHandle.Set( pNewParent );
  1973. if (newParentHandle.ToInt() == m_pMoveParent.ToInt())
  1974. return;
  1975. if (m_pMoveParent.IsValid())
  1976. {
  1977. UnlinkChild( m_pMoveParent, this );
  1978. }
  1979. if (pNewParent)
  1980. {
  1981. LinkChild( pNewParent, this );
  1982. }
  1983. InvalidatePhysicsRecursive( POSITION_CHANGED | ANGLES_CHANGED | VELOCITY_CHANGED );
  1984. #ifdef TF_CLIENT_DLL
  1985. m_bValidatedOwner = false;
  1986. #endif
  1987. }
  1988. //-----------------------------------------------------------------------------
  1989. // Unlinks from hierarchy
  1990. //-----------------------------------------------------------------------------
  1991. void C_BaseEntity::SetParent( C_BaseEntity *pParentEntity, int iParentAttachment )
  1992. {
  1993. // NOTE: This version is meant to be called *outside* of PostDataUpdate
  1994. // as it assumes the moveparent has a valid handle
  1995. EHANDLE newParentHandle;
  1996. newParentHandle.Set( pParentEntity );
  1997. if (newParentHandle.ToInt() == m_pMoveParent.ToInt())
  1998. return;
  1999. // NOTE: Have to do this before the unlink to ensure local coords are valid
  2000. Vector vecAbsOrigin = GetAbsOrigin();
  2001. QAngle angAbsRotation = GetAbsAngles();
  2002. Vector vecAbsVelocity = GetAbsVelocity();
  2003. // First deal with unlinking
  2004. if (m_pMoveParent.IsValid())
  2005. {
  2006. UnlinkChild( m_pMoveParent, this );
  2007. }
  2008. if (pParentEntity)
  2009. {
  2010. LinkChild( pParentEntity, this );
  2011. }
  2012. if ( !IsServerEntity() )
  2013. {
  2014. m_hNetworkMoveParent = pParentEntity;
  2015. }
  2016. m_iParentAttachment = iParentAttachment;
  2017. m_vecAbsOrigin.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  2018. m_angAbsRotation.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  2019. m_vecAbsVelocity.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  2020. SetAbsOrigin(vecAbsOrigin);
  2021. SetAbsAngles(angAbsRotation);
  2022. SetAbsVelocity(vecAbsVelocity);
  2023. }
  2024. //-----------------------------------------------------------------------------
  2025. // Unlinks from hierarchy
  2026. //-----------------------------------------------------------------------------
  2027. void C_BaseEntity::UnlinkFromHierarchy()
  2028. {
  2029. // Clear out links if we're out of the picture...
  2030. if ( m_pMoveParent.IsValid() )
  2031. {
  2032. UnlinkChild( m_pMoveParent, this );
  2033. }
  2034. //Adrian: This was causing problems with the local network backdoor with entities coming in and out of the PVS at certain times.
  2035. //This would work fine if a full entity update was coming (caused by certain factors like too many entities entering the pvs at once).
  2036. //but otherwise it would not detect the change on the client (since the server and client shouldn't be out of sync) and the var would not be updated like it should.
  2037. //m_iParentAttachment = 0;
  2038. // unlink also all move children
  2039. C_BaseEntity *pChild = FirstMoveChild();
  2040. while( pChild )
  2041. {
  2042. if ( pChild->m_pMoveParent != this )
  2043. {
  2044. Warning( "C_BaseEntity::UnlinkFromHierarchy(): Entity has a child with the wrong parent!\n" );
  2045. Assert( 0 );
  2046. UnlinkChild( this, pChild );
  2047. pChild->UnlinkFromHierarchy();
  2048. }
  2049. else
  2050. pChild->UnlinkFromHierarchy();
  2051. pChild = FirstMoveChild();
  2052. }
  2053. }
  2054. //-----------------------------------------------------------------------------
  2055. // Purpose: Make sure that the correct model is referenced for this entity
  2056. //-----------------------------------------------------------------------------
  2057. void C_BaseEntity::ValidateModelIndex( void )
  2058. {
  2059. #ifdef TF_CLIENT_DLL
  2060. if ( m_nModelIndexOverrides[VISION_MODE_NONE] > 0 )
  2061. {
  2062. if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_HALLOWEEN ) )
  2063. {
  2064. if ( m_nModelIndexOverrides[VISION_MODE_HALLOWEEN] > 0 )
  2065. {
  2066. SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_HALLOWEEN] );
  2067. return;
  2068. }
  2069. }
  2070. if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO ) )
  2071. {
  2072. if ( m_nModelIndexOverrides[VISION_MODE_PYRO] > 0 )
  2073. {
  2074. SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_PYRO] );
  2075. return;
  2076. }
  2077. }
  2078. if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_ROME ) )
  2079. {
  2080. if ( m_nModelIndexOverrides[VISION_MODE_ROME] > 0 )
  2081. {
  2082. SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_ROME] );
  2083. return;
  2084. }
  2085. }
  2086. SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_NONE] );
  2087. return;
  2088. }
  2089. #endif
  2090. SetModelByIndex( m_nModelIndex );
  2091. }
  2092. //-----------------------------------------------------------------------------
  2093. // Purpose: Entity data has been parsed and unpacked. Now do any necessary decoding, munging
  2094. // Input : bnewentity - was this entity new in this update packet?
  2095. //-----------------------------------------------------------------------------
  2096. void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType )
  2097. {
  2098. MDLCACHE_CRITICAL_SECTION();
  2099. PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, "postdataupdate" );
  2100. // NOTE: This *has* to happen first. Otherwise, Origin + angles may be wrong
  2101. if ( m_nRenderFX == kRenderFxRagdoll && updateType == DATA_UPDATE_CREATED )
  2102. {
  2103. MoveToLastReceivedPosition( true );
  2104. }
  2105. else
  2106. {
  2107. MoveToLastReceivedPosition( false );
  2108. }
  2109. // If it's the world, force solid flags
  2110. if ( index == 0 )
  2111. {
  2112. m_nModelIndex = 1;
  2113. SetSolid( SOLID_BSP );
  2114. // FIXME: Should these be assertions?
  2115. SetAbsOrigin( vec3_origin );
  2116. SetAbsAngles( vec3_angle );
  2117. }
  2118. if ( m_nOldRenderMode != m_nRenderMode )
  2119. {
  2120. SetRenderMode( (RenderMode_t)m_nRenderMode, true );
  2121. }
  2122. bool animTimeChanged = ( m_flAnimTime != m_flOldAnimTime ) ? true : false;
  2123. bool originChanged = ( m_vecOldOrigin != GetLocalOrigin() ) ? true : false;
  2124. bool anglesChanged = ( m_vecOldAngRotation != GetLocalAngles() ) ? true : false;
  2125. bool simTimeChanged = ( m_flSimulationTime != m_flOldSimulationTime ) ? true : false;
  2126. // Detect simulation changes
  2127. bool simulationChanged = originChanged || anglesChanged || simTimeChanged;
  2128. bool bPredictable = GetPredictable();
  2129. // For non-predicted and non-client only ents, we need to latch network values into the interpolation histories
  2130. if ( !bPredictable && !IsClientCreated() )
  2131. {
  2132. if ( animTimeChanged )
  2133. {
  2134. OnLatchInterpolatedVariables( LATCH_ANIMATION_VAR );
  2135. }
  2136. if ( simulationChanged )
  2137. {
  2138. OnLatchInterpolatedVariables( LATCH_SIMULATION_VAR );
  2139. }
  2140. }
  2141. // For predictables, we also need to store off the last networked value
  2142. else if ( bPredictable )
  2143. {
  2144. // Just store off last networked value for use in prediction
  2145. OnStoreLastNetworkedValue();
  2146. }
  2147. // Deal with hierarchy. Have to do it here (instead of in a proxy)
  2148. // because this is the only point at which all entities are loaded
  2149. // If this condition isn't met, then a child was sent without its parent
  2150. Assert( m_hNetworkMoveParent.Get() || !m_hNetworkMoveParent.IsValid() );
  2151. HierarchySetParent(m_hNetworkMoveParent);
  2152. MarkMessageReceived();
  2153. // Make sure that the correct model is referenced for this entity
  2154. ValidateModelIndex();
  2155. // If this entity was new, then latch in various values no matter what.
  2156. if ( updateType == DATA_UPDATE_CREATED )
  2157. {
  2158. // Construct a random value for this instance
  2159. m_flProxyRandomValue = random->RandomFloat( 0, 1 );
  2160. ResetLatched();
  2161. m_nCreationTick = gpGlobals->tickcount;
  2162. }
  2163. CheckInitPredictable( "PostDataUpdate" );
  2164. // It's possible that a new entity will need to be forceably added to the
  2165. // player simulation list. If so, do this here
  2166. #if !defined( NO_ENTITY_PREDICTION )
  2167. C_BasePlayer *local = C_BasePlayer::GetLocalPlayer();
  2168. if ( IsPlayerSimulated() &&
  2169. ( NULL != local ) &&
  2170. ( local == m_hOwnerEntity ) )
  2171. {
  2172. // Make sure player is driving simulation (field is only ever sent to local player)
  2173. SetPlayerSimulated( local );
  2174. }
  2175. #endif
  2176. UpdatePartitionListEntry();
  2177. // Add the entity to the nointerp list.
  2178. if ( !IsClientCreated() )
  2179. {
  2180. if ( Teleported() || IsNoInterpolationFrame() )
  2181. AddToTeleportList();
  2182. }
  2183. // if we changed parents, recalculate visibility
  2184. if ( m_hOldMoveParent != m_hNetworkMoveParent )
  2185. {
  2186. UpdateVisibility();
  2187. }
  2188. }
  2189. //-----------------------------------------------------------------------------
  2190. // Purpose:
  2191. // Input : *context -
  2192. //-----------------------------------------------------------------------------
  2193. void C_BaseEntity::CheckInitPredictable( const char *context )
  2194. {
  2195. #if !defined( NO_ENTITY_PREDICTION )
  2196. // Prediction is disabled
  2197. if ( !cl_predict->GetInt() )
  2198. return;
  2199. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  2200. if ( !player )
  2201. return;
  2202. if ( !GetPredictionEligible() )
  2203. {
  2204. if ( m_PredictableID.IsActive() &&
  2205. ( player->index - 1 ) == m_PredictableID.GetPlayer() )
  2206. {
  2207. // If it comes through with an ID, it should be eligible
  2208. SetPredictionEligible( true );
  2209. }
  2210. else
  2211. {
  2212. return;
  2213. }
  2214. }
  2215. if ( IsClientCreated() )
  2216. return;
  2217. if ( !ShouldPredict() )
  2218. return;
  2219. if ( IsIntermediateDataAllocated() )
  2220. return;
  2221. // Msg( "Predicting init %s at %s\n", GetClassname(), context );
  2222. InitPredictable();
  2223. #endif
  2224. }
  2225. bool C_BaseEntity::IsSelfAnimating()
  2226. {
  2227. return true;
  2228. }
  2229. //-----------------------------------------------------------------------------
  2230. // EFlags..
  2231. //-----------------------------------------------------------------------------
  2232. int C_BaseEntity::GetEFlags() const
  2233. {
  2234. return m_iEFlags;
  2235. }
  2236. void C_BaseEntity::SetEFlags( int iEFlags )
  2237. {
  2238. m_iEFlags = iEFlags;
  2239. }
  2240. //-----------------------------------------------------------------------------
  2241. // Sets the model...
  2242. //-----------------------------------------------------------------------------
  2243. void C_BaseEntity::SetModelByIndex( int nModelIndex )
  2244. {
  2245. SetModelIndex( nModelIndex );
  2246. }
  2247. //-----------------------------------------------------------------------------
  2248. // Set model... (NOTE: Should only be used by client-only entities
  2249. //-----------------------------------------------------------------------------
  2250. bool C_BaseEntity::SetModel( const char *pModelName )
  2251. {
  2252. if ( pModelName )
  2253. {
  2254. int nModelIndex = modelinfo->GetModelIndex( pModelName );
  2255. SetModelByIndex( nModelIndex );
  2256. return ( nModelIndex != -1 );
  2257. }
  2258. else
  2259. {
  2260. SetModelByIndex( -1 );
  2261. return false;
  2262. }
  2263. }
  2264. void C_BaseEntity::OnStoreLastNetworkedValue()
  2265. {
  2266. bool bRestore = false;
  2267. Vector savePos;
  2268. QAngle saveAng;
  2269. // Kind of a hack, but we want to latch the actual networked value for origin/angles, not what's sitting in m_vecOrigin in the
  2270. // ragdoll case where we don't copy it over in MoveToLastNetworkOrigin
  2271. if ( m_nRenderFX == kRenderFxRagdoll && GetPredictable() )
  2272. {
  2273. bRestore = true;
  2274. savePos = GetLocalOrigin();
  2275. saveAng = GetLocalAngles();
  2276. MoveToLastReceivedPosition( true );
  2277. }
  2278. int c = m_VarMap.m_Entries.Count();
  2279. for ( int i = 0; i < c; i++ )
  2280. {
  2281. VarMapEntry_t *e = &m_VarMap.m_Entries[ i ];
  2282. IInterpolatedVar *watcher = e->watcher;
  2283. int type = watcher->GetType();
  2284. if ( type & EXCLUDE_AUTO_LATCH )
  2285. continue;
  2286. watcher->NoteLastNetworkedValue();
  2287. }
  2288. if ( bRestore )
  2289. {
  2290. SetLocalOrigin( savePos );
  2291. SetLocalAngles( saveAng );
  2292. }
  2293. }
  2294. //-----------------------------------------------------------------------------
  2295. // Purpose: The animtime is about to be changed in a network update, store off various fields so that
  2296. // we can use them to do blended sequence transitions, etc.
  2297. // Input : *pState - the (mostly) previous state data
  2298. //-----------------------------------------------------------------------------
  2299. void C_BaseEntity::OnLatchInterpolatedVariables( int flags )
  2300. {
  2301. float changetime = GetLastChangeTime( flags );
  2302. bool bUpdateLastNetworkedValue = !(flags & INTERPOLATE_OMIT_UPDATE_LAST_NETWORKED) ? true : false;
  2303. PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, bUpdateLastNetworkedValue ? "latch+net" : "latch" );
  2304. int c = m_VarMap.m_Entries.Count();
  2305. for ( int i = 0; i < c; i++ )
  2306. {
  2307. VarMapEntry_t *e = &m_VarMap.m_Entries[ i ];
  2308. IInterpolatedVar *watcher = e->watcher;
  2309. int type = watcher->GetType();
  2310. if ( !(type & flags) )
  2311. continue;
  2312. if ( type & EXCLUDE_AUTO_LATCH )
  2313. continue;
  2314. if ( watcher->NoteChanged( changetime, bUpdateLastNetworkedValue ) )
  2315. e->m_bNeedsToInterpolate = true;
  2316. }
  2317. if ( ShouldInterpolate() )
  2318. {
  2319. AddToInterpolationList();
  2320. }
  2321. }
  2322. int CBaseEntity::BaseInterpolatePart1( float &currentTime, Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int &bNoMoreChanges )
  2323. {
  2324. // Don't mess with the world!!!
  2325. bNoMoreChanges = 1;
  2326. // These get moved to the parent position automatically
  2327. if ( IsFollowingEntity() || !IsInterpolationEnabled() )
  2328. {
  2329. // Assume current origin ( no interpolation )
  2330. MoveToLastReceivedPosition();
  2331. return INTERPOLATE_STOP;
  2332. }
  2333. if ( GetPredictable() || IsClientCreated() )
  2334. {
  2335. C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
  2336. if ( localplayer && currentTime == gpGlobals->curtime )
  2337. {
  2338. currentTime = localplayer->GetFinalPredictedTime();
  2339. currentTime -= TICK_INTERVAL;
  2340. currentTime += ( gpGlobals->interpolation_amount * TICK_INTERVAL );
  2341. }
  2342. }
  2343. oldOrigin = m_vecOrigin;
  2344. oldAngles = m_angRotation;
  2345. oldVel = m_vecVelocity;
  2346. bNoMoreChanges = Interp_Interpolate( GetVarMapping(), currentTime );
  2347. if ( cl_interp_all.GetInt() || (m_EntClientFlags & ENTCLIENTFLAG_ALWAYS_INTERPOLATE) )
  2348. bNoMoreChanges = 0;
  2349. return INTERPOLATE_CONTINUE;
  2350. }
  2351. #if 0
  2352. static ConVar cl_watchplayer( "cl_watchplayer", "-1", 0 );
  2353. #endif
  2354. void C_BaseEntity::BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int nChangeFlags )
  2355. {
  2356. if ( m_vecOrigin != oldOrigin )
  2357. {
  2358. nChangeFlags |= POSITION_CHANGED;
  2359. }
  2360. if( m_angRotation != oldAngles )
  2361. {
  2362. nChangeFlags |= ANGLES_CHANGED;
  2363. }
  2364. if ( m_vecVelocity != oldVel )
  2365. {
  2366. nChangeFlags |= VELOCITY_CHANGED;
  2367. }
  2368. if ( nChangeFlags != 0 )
  2369. {
  2370. InvalidatePhysicsRecursive( nChangeFlags );
  2371. }
  2372. #if 0
  2373. if ( index == 1 )
  2374. {
  2375. SpewInterpolatedVar( &m_iv_vecOrigin, gpGlobals->curtime, GetInterpolationAmount( LATCH_SIMULATION_VAR ), true );
  2376. }
  2377. #endif
  2378. }
  2379. //-----------------------------------------------------------------------------
  2380. // Purpose: Default interpolation for entities
  2381. // Output : true means entity should be drawn, false means probably not
  2382. //-----------------------------------------------------------------------------
  2383. bool C_BaseEntity::Interpolate( float currentTime )
  2384. {
  2385. VPROF( "C_BaseEntity::Interpolate" );
  2386. Vector oldOrigin;
  2387. QAngle oldAngles;
  2388. Vector oldVel;
  2389. int bNoMoreChanges;
  2390. int retVal = BaseInterpolatePart1( currentTime, oldOrigin, oldAngles, oldVel, bNoMoreChanges );
  2391. // If all the Interpolate() calls returned that their values aren't going to
  2392. // change anymore, then get us out of the interpolation list.
  2393. if ( bNoMoreChanges )
  2394. RemoveFromInterpolationList();
  2395. if ( retVal == INTERPOLATE_STOP )
  2396. return true;
  2397. int nChangeFlags = 0;
  2398. BaseInterpolatePart2( oldOrigin, oldAngles, oldVel, nChangeFlags );
  2399. return true;
  2400. }
  2401. CStudioHdr *C_BaseEntity::OnNewModel()
  2402. {
  2403. #ifdef TF_CLIENT_DLL
  2404. m_bValidatedOwner = false;
  2405. #endif
  2406. return NULL;
  2407. }
  2408. void C_BaseEntity::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
  2409. {
  2410. return;
  2411. }
  2412. // Above this velocity and we'll assume a warp/teleport
  2413. #define MAX_INTERPOLATE_VELOCITY 4000.0f
  2414. #define MAX_INTERPOLATE_VELOCITY_PLAYER 1250.0f
  2415. //-----------------------------------------------------------------------------
  2416. // Purpose: Determine whether entity was teleported ( so we can disable interpolation )
  2417. // Input : *ent -
  2418. // Output : bool
  2419. //-----------------------------------------------------------------------------
  2420. bool C_BaseEntity::Teleported( void )
  2421. {
  2422. // Disable interpolation when hierarchy changes
  2423. if (m_hOldMoveParent != m_hNetworkMoveParent || m_iOldParentAttachment != m_iParentAttachment)
  2424. {
  2425. return true;
  2426. }
  2427. return false;
  2428. }
  2429. //-----------------------------------------------------------------------------
  2430. // Purpose: Is this a submodel of the world ( model name starts with * )?
  2431. // Output : Returns true on success, false on failure.
  2432. //-----------------------------------------------------------------------------
  2433. bool C_BaseEntity::IsSubModel( void )
  2434. {
  2435. if ( model &&
  2436. modelinfo->GetModelType( model ) == mod_brush &&
  2437. modelinfo->GetModelName( model )[0] == '*' )
  2438. {
  2439. return true;
  2440. }
  2441. return false;
  2442. }
  2443. //-----------------------------------------------------------------------------
  2444. // Purpose: Create entity lighting effects
  2445. //-----------------------------------------------------------------------------
  2446. void C_BaseEntity::CreateLightEffects( void )
  2447. {
  2448. dlight_t *dl;
  2449. // Is this for player flashlights only, if so move to linkplayers?
  2450. if ( index == render->GetViewEntity() )
  2451. return;
  2452. if (IsEffectActive(EF_BRIGHTLIGHT))
  2453. {
  2454. dl = effects->CL_AllocDlight ( index );
  2455. dl->origin = GetAbsOrigin();
  2456. dl->origin[2] += 16;
  2457. dl->color.r = dl->color.g = dl->color.b = 250;
  2458. dl->radius = random->RandomFloat(400,431);
  2459. dl->die = gpGlobals->curtime + 0.001;
  2460. }
  2461. if (IsEffectActive(EF_DIMLIGHT))
  2462. {
  2463. dl = effects->CL_AllocDlight ( index );
  2464. dl->origin = GetAbsOrigin();
  2465. dl->color.r = dl->color.g = dl->color.b = 100;
  2466. dl->radius = random->RandomFloat(200,231);
  2467. dl->die = gpGlobals->curtime + 0.001;
  2468. }
  2469. }
  2470. void C_BaseEntity::MoveToLastReceivedPosition( bool force )
  2471. {
  2472. if ( force || ( m_nRenderFX != kRenderFxRagdoll ) )
  2473. {
  2474. SetLocalOrigin( GetNetworkOrigin() );
  2475. SetLocalAngles( GetNetworkAngles() );
  2476. }
  2477. }
  2478. bool C_BaseEntity::ShouldInterpolate()
  2479. {
  2480. if ( render->GetViewEntity() == index )
  2481. return true;
  2482. if ( index == 0 || !GetModel() )
  2483. return false;
  2484. // always interpolate if visible
  2485. if ( IsVisible() )
  2486. return true;
  2487. // if any movement child needs interpolation, we have to interpolate too
  2488. C_BaseEntity *pChild = FirstMoveChild();
  2489. while( pChild )
  2490. {
  2491. if ( pChild->ShouldInterpolate() )
  2492. return true;
  2493. pChild = pChild->NextMovePeer();
  2494. }
  2495. // don't interpolate
  2496. return false;
  2497. }
  2498. void C_BaseEntity::ProcessTeleportList()
  2499. {
  2500. int iNext;
  2501. for ( int iCur=g_TeleportList.Head(); iCur != g_TeleportList.InvalidIndex(); iCur=iNext )
  2502. {
  2503. iNext = g_TeleportList.Next( iCur );
  2504. C_BaseEntity *pCur = g_TeleportList[iCur];
  2505. bool teleport = pCur->Teleported();
  2506. bool ef_nointerp = pCur->IsNoInterpolationFrame();
  2507. if ( teleport || ef_nointerp )
  2508. {
  2509. // Undo the teleport flag..
  2510. pCur->m_hOldMoveParent = pCur->m_hNetworkMoveParent;
  2511. pCur->m_iOldParentAttachment = pCur->m_iParentAttachment;
  2512. // Zero out all but last update.
  2513. pCur->MoveToLastReceivedPosition( true );
  2514. pCur->ResetLatched();
  2515. }
  2516. else
  2517. {
  2518. // Get it out of the list as soon as we can.
  2519. pCur->RemoveFromTeleportList();
  2520. }
  2521. }
  2522. }
  2523. void C_BaseEntity::CheckInterpolatedVarParanoidMeasurement()
  2524. {
  2525. // What we're doing here is to check all the entities that were not in the interpolation
  2526. // list and make sure that there's no entity that should be in the list that isn't.
  2527. #ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT
  2528. int iHighest = ClientEntityList().GetHighestEntityIndex();
  2529. for ( int i=0; i <= iHighest; i++ )
  2530. {
  2531. C_BaseEntity *pEnt = ClientEntityList().GetBaseEntity( i );
  2532. if ( !pEnt || pEnt->m_InterpolationListEntry != 0xFFFF || !pEnt->ShouldInterpolate() )
  2533. continue;
  2534. // Player angles always generates this error when the console is up.
  2535. if ( pEnt->entindex() == 1 && engine->Con_IsVisible() )
  2536. continue;
  2537. // View models tend to screw up this test unnecesarily because they modify origin,
  2538. // angles, and
  2539. if ( dynamic_cast<C_BaseViewModel*>( pEnt ) )
  2540. continue;
  2541. g_bRestoreInterpolatedVarValues = true;
  2542. g_nInterpolatedVarsChanged = 0;
  2543. pEnt->Interpolate( gpGlobals->curtime );
  2544. g_bRestoreInterpolatedVarValues = false;
  2545. if ( g_nInterpolatedVarsChanged > 0 )
  2546. {
  2547. static int iWarningCount = 0;
  2548. Warning( "(%d): An entity (%d) should have been in g_InterpolationList.\n", iWarningCount++, pEnt->entindex() );
  2549. break;
  2550. }
  2551. }
  2552. #endif
  2553. }
  2554. void C_BaseEntity::ProcessInterpolatedList()
  2555. {
  2556. CheckInterpolatedVarParanoidMeasurement();
  2557. // Interpolate the minimal set of entities that need it.
  2558. int iNext;
  2559. for ( int iCur=g_InterpolationList.Head(); iCur != g_InterpolationList.InvalidIndex(); iCur=iNext )
  2560. {
  2561. iNext = g_InterpolationList.Next( iCur );
  2562. C_BaseEntity *pCur = g_InterpolationList[iCur];
  2563. pCur->m_bReadyToDraw = pCur->Interpolate( gpGlobals->curtime );
  2564. }
  2565. }
  2566. //-----------------------------------------------------------------------------
  2567. // Purpose: Add entity to visibile entities list
  2568. //-----------------------------------------------------------------------------
  2569. void C_BaseEntity::AddEntity( void )
  2570. {
  2571. // Don't ever add the world, it's drawn separately
  2572. if ( index == 0 )
  2573. return;
  2574. // Create flashlight effects, etc.
  2575. CreateLightEffects();
  2576. }
  2577. //-----------------------------------------------------------------------------
  2578. // Returns the aiment render origin + angles
  2579. //-----------------------------------------------------------------------------
  2580. void C_BaseEntity::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles )
  2581. {
  2582. // Should be overridden for things that attach to attchment points
  2583. // Slam origin to the origin of the entity we are attached to...
  2584. *pOrigin = pAttachedTo->GetAbsOrigin();
  2585. *pAngles = pAttachedTo->GetAbsAngles();
  2586. }
  2587. void C_BaseEntity::StopFollowingEntity( )
  2588. {
  2589. Assert( IsFollowingEntity() );
  2590. SetParent( NULL );
  2591. RemoveEffects( EF_BONEMERGE );
  2592. RemoveSolidFlags( FSOLID_NOT_SOLID );
  2593. SetMoveType( MOVETYPE_NONE );
  2594. }
  2595. bool C_BaseEntity::IsFollowingEntity()
  2596. {
  2597. return IsEffectActive(EF_BONEMERGE) && (GetMoveType() == MOVETYPE_NONE) && GetMoveParent();
  2598. }
  2599. C_BaseEntity *CBaseEntity::GetFollowedEntity()
  2600. {
  2601. if (!IsFollowingEntity())
  2602. return NULL;
  2603. return GetMoveParent();
  2604. }
  2605. //-----------------------------------------------------------------------------
  2606. // Default implementation for GetTextureAnimationStartTime
  2607. //-----------------------------------------------------------------------------
  2608. float C_BaseEntity::GetTextureAnimationStartTime()
  2609. {
  2610. return m_flSpawnTime;
  2611. }
  2612. //-----------------------------------------------------------------------------
  2613. // Default implementation, indicates that a texture animation has wrapped
  2614. //-----------------------------------------------------------------------------
  2615. void C_BaseEntity::TextureAnimationWrapped()
  2616. {
  2617. }
  2618. void C_BaseEntity::ClientThink()
  2619. {
  2620. }
  2621. void C_BaseEntity::Simulate()
  2622. {
  2623. AddEntity(); // Legacy support. Once-per-frame stuff should go in Simulate().
  2624. }
  2625. // Defined in engine
  2626. static ConVar cl_interpolate( "cl_interpolate", "1.0f", FCVAR_USERINFO | FCVAR_DEVELOPMENTONLY );
  2627. // (static function)
  2628. void C_BaseEntity::InterpolateServerEntities()
  2629. {
  2630. VPROF_BUDGET( "C_BaseEntity::InterpolateServerEntities", VPROF_BUDGETGROUP_INTERPOLATION );
  2631. s_bInterpolate = cl_interpolate.GetBool();
  2632. // Don't interpolate during timedemo playback
  2633. if ( engine->IsPlayingTimeDemo() || engine->IsPaused() )
  2634. {
  2635. s_bInterpolate = false;
  2636. }
  2637. if ( !engine->IsPlayingDemo() )
  2638. {
  2639. // Don't interpolate, either, if we are timing out
  2640. INetChannelInfo *nci = engine->GetNetChannelInfo();
  2641. if ( nci && nci->GetTimeSinceLastReceived() > 0.5f )
  2642. {
  2643. s_bInterpolate = false;
  2644. }
  2645. }
  2646. if ( IsSimulatingOnAlternateTicks() != g_bWasSkipping || IsEngineThreaded() != g_bWasThreaded )
  2647. {
  2648. g_bWasSkipping = IsSimulatingOnAlternateTicks();
  2649. g_bWasThreaded = IsEngineThreaded();
  2650. C_BaseEntityIterator iterator;
  2651. C_BaseEntity *pEnt;
  2652. while ( (pEnt = iterator.Next()) != NULL )
  2653. {
  2654. pEnt->Interp_UpdateInterpolationAmounts( pEnt->GetVarMapping() );
  2655. }
  2656. }
  2657. // Enable extrapolation?
  2658. CInterpolationContext context;
  2659. context.SetLastTimeStamp( engine->GetLastTimeStamp() );
  2660. if ( cl_extrapolate.GetBool() && !engine->IsPaused() )
  2661. {
  2662. context.EnableExtrapolation( true );
  2663. }
  2664. // Smoothly interpolate position for server entities.
  2665. ProcessTeleportList();
  2666. ProcessInterpolatedList();
  2667. }
  2668. // (static function)
  2669. void C_BaseEntity::AddVisibleEntities()
  2670. {
  2671. #if !defined( NO_ENTITY_PREDICTION )
  2672. VPROF_BUDGET( "C_BaseEntity::AddVisibleEntities", VPROF_BUDGETGROUP_WORLD_RENDERING );
  2673. // Let non-dormant client created predictables get added, too
  2674. int c = predictables->GetPredictableCount();
  2675. for ( int i = 0 ; i < c ; i++ )
  2676. {
  2677. C_BaseEntity *pEnt = predictables->GetPredictable( i );
  2678. if ( !pEnt )
  2679. continue;
  2680. if ( !pEnt->IsClientCreated() )
  2681. continue;
  2682. // Only draw until it's ack'd since that means a real entity has arrived
  2683. if ( pEnt->m_PredictableID.GetAcknowledged() )
  2684. continue;
  2685. // Don't draw if dormant
  2686. if ( pEnt->IsDormantPredictable() )
  2687. continue;
  2688. pEnt->UpdateVisibility();
  2689. }
  2690. #endif
  2691. }
  2692. //-----------------------------------------------------------------------------
  2693. // Purpose:
  2694. // Input : type -
  2695. //-----------------------------------------------------------------------------
  2696. void C_BaseEntity::OnPreDataChanged( DataUpdateType_t type )
  2697. {
  2698. m_hOldMoveParent = m_hNetworkMoveParent;
  2699. m_iOldParentAttachment = m_iParentAttachment;
  2700. }
  2701. void C_BaseEntity::OnDataChanged( DataUpdateType_t type )
  2702. {
  2703. // See if it needs to allocate prediction stuff
  2704. CheckInitPredictable( "OnDataChanged" );
  2705. // Set up shadows; do it here so that objects can change shadowcasting state
  2706. CreateShadow();
  2707. if ( type == DATA_UPDATE_CREATED )
  2708. {
  2709. UpdateVisibility();
  2710. }
  2711. }
  2712. ClientThinkHandle_t C_BaseEntity::GetThinkHandle()
  2713. {
  2714. return m_hThink;
  2715. }
  2716. void C_BaseEntity::SetThinkHandle( ClientThinkHandle_t hThink )
  2717. {
  2718. m_hThink = hThink;
  2719. }
  2720. //-----------------------------------------------------------------------------
  2721. // Purpose: This routine modulates renderamt according to m_nRenderFX's value
  2722. // This is a client side effect and will not be in-sync on machines across a
  2723. // network game.
  2724. // Input : origin -
  2725. // alpha -
  2726. // Output : int
  2727. //-----------------------------------------------------------------------------
  2728. void C_BaseEntity::ComputeFxBlend( void )
  2729. {
  2730. // Don't recompute if we've already computed this frame
  2731. if ( m_nFXComputeFrame == gpGlobals->framecount )
  2732. return;
  2733. MDLCACHE_CRITICAL_SECTION();
  2734. int blend=0;
  2735. float offset;
  2736. offset = ((int)index) * 363.0;// Use ent index to de-sync these fx
  2737. switch( m_nRenderFX )
  2738. {
  2739. case kRenderFxPulseSlowWide:
  2740. blend = m_clrRender->a + 0x40 * sin( gpGlobals->curtime * 2 + offset );
  2741. break;
  2742. case kRenderFxPulseFastWide:
  2743. blend = m_clrRender->a + 0x40 * sin( gpGlobals->curtime * 8 + offset );
  2744. break;
  2745. case kRenderFxPulseFastWider:
  2746. blend = ( 0xff * fabs(sin( gpGlobals->curtime * 12 + offset ) ) );
  2747. break;
  2748. case kRenderFxPulseSlow:
  2749. blend = m_clrRender->a + 0x10 * sin( gpGlobals->curtime * 2 + offset );
  2750. break;
  2751. case kRenderFxPulseFast:
  2752. blend = m_clrRender->a + 0x10 * sin( gpGlobals->curtime * 8 + offset );
  2753. break;
  2754. // JAY: HACK for now -- not time based
  2755. case kRenderFxFadeSlow:
  2756. if ( m_clrRender->a > 0 )
  2757. {
  2758. SetRenderColorA( m_clrRender->a - 1 );
  2759. }
  2760. else
  2761. {
  2762. SetRenderColorA( 0 );
  2763. }
  2764. blend = m_clrRender->a;
  2765. break;
  2766. case kRenderFxFadeFast:
  2767. if ( m_clrRender->a > 3 )
  2768. {
  2769. SetRenderColorA( m_clrRender->a - 4 );
  2770. }
  2771. else
  2772. {
  2773. SetRenderColorA( 0 );
  2774. }
  2775. blend = m_clrRender->a;
  2776. break;
  2777. case kRenderFxSolidSlow:
  2778. if ( m_clrRender->a < 255 )
  2779. {
  2780. SetRenderColorA( m_clrRender->a + 1 );
  2781. }
  2782. else
  2783. {
  2784. SetRenderColorA( 255 );
  2785. }
  2786. blend = m_clrRender->a;
  2787. break;
  2788. case kRenderFxSolidFast:
  2789. if ( m_clrRender->a < 252 )
  2790. {
  2791. SetRenderColorA( m_clrRender->a + 4 );
  2792. }
  2793. else
  2794. {
  2795. SetRenderColorA( 255 );
  2796. }
  2797. blend = m_clrRender->a;
  2798. break;
  2799. case kRenderFxStrobeSlow:
  2800. blend = 20 * sin( gpGlobals->curtime * 4 + offset );
  2801. if ( blend < 0 )
  2802. {
  2803. blend = 0;
  2804. }
  2805. else
  2806. {
  2807. blend = m_clrRender->a;
  2808. }
  2809. break;
  2810. case kRenderFxStrobeFast:
  2811. blend = 20 * sin( gpGlobals->curtime * 16 + offset );
  2812. if ( blend < 0 )
  2813. {
  2814. blend = 0;
  2815. }
  2816. else
  2817. {
  2818. blend = m_clrRender->a;
  2819. }
  2820. break;
  2821. case kRenderFxStrobeFaster:
  2822. blend = 20 * sin( gpGlobals->curtime * 36 + offset );
  2823. if ( blend < 0 )
  2824. {
  2825. blend = 0;
  2826. }
  2827. else
  2828. {
  2829. blend = m_clrRender->a;
  2830. }
  2831. break;
  2832. case kRenderFxFlickerSlow:
  2833. blend = 20 * (sin( gpGlobals->curtime * 2 ) + sin( gpGlobals->curtime * 17 + offset ));
  2834. if ( blend < 0 )
  2835. {
  2836. blend = 0;
  2837. }
  2838. else
  2839. {
  2840. blend = m_clrRender->a;
  2841. }
  2842. break;
  2843. case kRenderFxFlickerFast:
  2844. blend = 20 * (sin( gpGlobals->curtime * 16 ) + sin( gpGlobals->curtime * 23 + offset ));
  2845. if ( blend < 0 )
  2846. {
  2847. blend = 0;
  2848. }
  2849. else
  2850. {
  2851. blend = m_clrRender->a;
  2852. }
  2853. break;
  2854. case kRenderFxHologram:
  2855. case kRenderFxDistort:
  2856. {
  2857. Vector tmp;
  2858. float dist;
  2859. VectorCopy( GetAbsOrigin(), tmp );
  2860. VectorSubtract( tmp, CurrentViewOrigin(), tmp );
  2861. dist = DotProduct( tmp, CurrentViewForward() );
  2862. // Turn off distance fade
  2863. if ( m_nRenderFX == kRenderFxDistort )
  2864. {
  2865. dist = 1;
  2866. }
  2867. if ( dist <= 0 )
  2868. {
  2869. blend = 0;
  2870. }
  2871. else
  2872. {
  2873. SetRenderColorA( 180 );
  2874. if ( dist <= 100 )
  2875. blend = m_clrRender->a;
  2876. else
  2877. blend = (int) ((1.0 - (dist - 100) * (1.0 / 400.0)) * m_clrRender->a);
  2878. blend += random->RandomInt(-32,31);
  2879. }
  2880. }
  2881. break;
  2882. case kRenderFxNone:
  2883. case kRenderFxClampMinScale:
  2884. default:
  2885. if (m_nRenderMode == kRenderNormal)
  2886. blend = 255;
  2887. else
  2888. blend = m_clrRender->a;
  2889. break;
  2890. }
  2891. blend = clamp( blend, 0, 255 );
  2892. // Look for client-side fades
  2893. unsigned char nFadeAlpha = GetClientSideFade();
  2894. if ( nFadeAlpha != 255 )
  2895. {
  2896. float flBlend = blend / 255.0f;
  2897. float flFade = nFadeAlpha / 255.0f;
  2898. blend = (int)( flBlend * flFade * 255.0f + 0.5f );
  2899. blend = clamp( blend, 0, 255 );
  2900. }
  2901. m_nRenderFXBlend = blend;
  2902. m_nFXComputeFrame = gpGlobals->framecount;
  2903. // Update the render group
  2904. if ( GetRenderHandle() != INVALID_CLIENT_RENDER_HANDLE )
  2905. {
  2906. ClientLeafSystem()->SetRenderGroup( GetRenderHandle(), GetRenderGroup() );
  2907. }
  2908. // Tell our shadow
  2909. if ( m_ShadowHandle != CLIENTSHADOW_INVALID_HANDLE )
  2910. {
  2911. g_pClientShadowMgr->SetFalloffBias( m_ShadowHandle, (255 - m_nRenderFXBlend) );
  2912. }
  2913. }
  2914. //-----------------------------------------------------------------------------
  2915. // Purpose:
  2916. //-----------------------------------------------------------------------------
  2917. int C_BaseEntity::GetFxBlend( void )
  2918. {
  2919. Assert( m_nFXComputeFrame == gpGlobals->framecount );
  2920. return m_nRenderFXBlend;
  2921. }
  2922. //-----------------------------------------------------------------------------
  2923. // Determine the color modulation amount
  2924. //-----------------------------------------------------------------------------
  2925. void C_BaseEntity::GetColorModulation( float* color )
  2926. {
  2927. color[0] = m_clrRender->r / 255.0f;
  2928. color[1] = m_clrRender->g / 255.0f;
  2929. color[2] = m_clrRender->b / 255.0f;
  2930. }
  2931. //-----------------------------------------------------------------------------
  2932. // Returns true if we should add this to the collision list
  2933. //-----------------------------------------------------------------------------
  2934. CollideType_t C_BaseEntity::GetCollideType( void )
  2935. {
  2936. if ( !m_nModelIndex || !model )
  2937. return ENTITY_SHOULD_NOT_COLLIDE;
  2938. if ( !IsSolid( ) )
  2939. return ENTITY_SHOULD_NOT_COLLIDE;
  2940. // If the model is a bsp or studio (i.e. it can collide with the player
  2941. if ( ( modelinfo->GetModelType( model ) != mod_brush ) && ( modelinfo->GetModelType( model ) != mod_studio ) )
  2942. return ENTITY_SHOULD_NOT_COLLIDE;
  2943. // Don't get stuck on point sized entities ( world doesn't count )
  2944. if ( m_nModelIndex != 1 )
  2945. {
  2946. if ( IsPointSized() )
  2947. return ENTITY_SHOULD_NOT_COLLIDE;
  2948. }
  2949. return ENTITY_SHOULD_COLLIDE;
  2950. }
  2951. //-----------------------------------------------------------------------------
  2952. // Is this a brush model?
  2953. //-----------------------------------------------------------------------------
  2954. bool C_BaseEntity::IsBrushModel() const
  2955. {
  2956. int modelType = modelinfo->GetModelType( model );
  2957. return (modelType == mod_brush);
  2958. }
  2959. //-----------------------------------------------------------------------------
  2960. // This method works when we've got a studio model
  2961. //-----------------------------------------------------------------------------
  2962. void C_BaseEntity::AddStudioDecal( const Ray_t& ray, int hitbox, int decalIndex,
  2963. bool doTrace, trace_t& tr, int maxLODToDecal )
  2964. {
  2965. if (doTrace)
  2966. {
  2967. enginetrace->ClipRayToEntity( ray, MASK_SHOT, this, &tr );
  2968. // Trace the ray against the entity
  2969. if (tr.fraction == 1.0f)
  2970. return;
  2971. // Set the trace index appropriately...
  2972. tr.m_pEnt = this;
  2973. }
  2974. // Exit out after doing the trace so any other effects that want to happen can happen.
  2975. if ( !r_drawmodeldecals.GetBool() )
  2976. return;
  2977. // Found the point, now lets apply the decals
  2978. CreateModelInstance();
  2979. // FIXME: Pass in decal up?
  2980. Vector up(0, 0, 1);
  2981. if (doTrace && (GetSolid() == SOLID_VPHYSICS) && !tr.startsolid && !tr.allsolid)
  2982. {
  2983. // Choose a more accurate normal direction
  2984. // Also, since we have more accurate info, we can avoid pokethru
  2985. Vector temp;
  2986. VectorSubtract( tr.endpos, tr.plane.normal, temp );
  2987. Ray_t betterRay;
  2988. betterRay.Init( tr.endpos, temp );
  2989. modelrender->AddDecal( m_ModelInstance, betterRay, up, decalIndex, GetStudioBody(), true, maxLODToDecal );
  2990. }
  2991. else
  2992. {
  2993. modelrender->AddDecal( m_ModelInstance, ray, up, decalIndex, GetStudioBody(), false, maxLODToDecal );
  2994. }
  2995. }
  2996. //-----------------------------------------------------------------------------
  2997. void C_BaseEntity::AddColoredStudioDecal( const Ray_t& ray, int hitbox, int decalIndex,
  2998. bool doTrace, trace_t& tr, Color cColor, int maxLODToDecal )
  2999. {
  3000. if (doTrace)
  3001. {
  3002. enginetrace->ClipRayToEntity( ray, MASK_SHOT, this, &tr );
  3003. // Trace the ray against the entity
  3004. if (tr.fraction == 1.0f)
  3005. return;
  3006. // Set the trace index appropriately...
  3007. tr.m_pEnt = this;
  3008. }
  3009. // Exit out after doing the trace so any other effects that want to happen can happen.
  3010. if ( !r_drawmodeldecals.GetBool() )
  3011. return;
  3012. // Found the point, now lets apply the decals
  3013. CreateModelInstance();
  3014. // FIXME: Pass in decal up?
  3015. Vector up(0, 0, 1);
  3016. if (doTrace && (GetSolid() == SOLID_VPHYSICS) && !tr.startsolid && !tr.allsolid)
  3017. {
  3018. // Choose a more accurate normal direction
  3019. // Also, since we have more accurate info, we can avoid pokethru
  3020. Vector temp;
  3021. VectorSubtract( tr.endpos, tr.plane.normal, temp );
  3022. Ray_t betterRay;
  3023. betterRay.Init( tr.endpos, temp );
  3024. modelrender->AddColoredDecal( m_ModelInstance, betterRay, up, decalIndex, GetStudioBody(), cColor, true, maxLODToDecal );
  3025. }
  3026. else
  3027. {
  3028. modelrender->AddColoredDecal( m_ModelInstance, ray, up, decalIndex, GetStudioBody(), cColor, false, maxLODToDecal );
  3029. }
  3030. }
  3031. //-----------------------------------------------------------------------------
  3032. // This method works when we've got a brush model
  3033. //-----------------------------------------------------------------------------
  3034. void C_BaseEntity::AddBrushModelDecal( const Ray_t& ray, const Vector& decalCenter,
  3035. int decalIndex, bool doTrace, trace_t& tr )
  3036. {
  3037. if ( doTrace )
  3038. {
  3039. enginetrace->ClipRayToEntity( ray, MASK_SHOT, this, &tr );
  3040. if ( tr.fraction == 1.0f )
  3041. return;
  3042. }
  3043. effects->DecalShoot( decalIndex, index,
  3044. model, GetAbsOrigin(), GetAbsAngles(), decalCenter, 0, 0 );
  3045. }
  3046. //-----------------------------------------------------------------------------
  3047. // A method to apply a decal to an entity
  3048. //-----------------------------------------------------------------------------
  3049. void C_BaseEntity::AddDecal( const Vector& rayStart, const Vector& rayEnd,
  3050. const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal )
  3051. {
  3052. Ray_t ray;
  3053. ray.Init( rayStart, rayEnd );
  3054. // FIXME: Better bloat?
  3055. // Bloat a little bit so we get the intersection
  3056. ray.m_Delta *= 1.1f;
  3057. int modelType = modelinfo->GetModelType( model );
  3058. switch ( modelType )
  3059. {
  3060. case mod_studio:
  3061. AddStudioDecal( ray, hitbox, decalIndex, doTrace, tr, maxLODToDecal );
  3062. break;
  3063. case mod_brush:
  3064. AddBrushModelDecal( ray, decalCenter, decalIndex, doTrace, tr );
  3065. break;
  3066. default:
  3067. // By default, no collision
  3068. tr.fraction = 1.0f;
  3069. break;
  3070. }
  3071. }
  3072. //-----------------------------------------------------------------------------
  3073. void C_BaseEntity::AddColoredDecal( const Vector& rayStart, const Vector& rayEnd,
  3074. const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, Color cColor, int maxLODToDecal )
  3075. {
  3076. Ray_t ray;
  3077. ray.Init( rayStart, rayEnd );
  3078. // FIXME: Better bloat?
  3079. // Bloat a little bit so we get the intersection
  3080. ray.m_Delta *= 1.1f;
  3081. int modelType = modelinfo->GetModelType( model );
  3082. if ( doTrace )
  3083. {
  3084. enginetrace->ClipRayToEntity( ray, MASK_SHOT, this, &tr );
  3085. switch ( modelType )
  3086. {
  3087. case mod_studio:
  3088. tr.m_pEnt = this;
  3089. break;
  3090. case mod_brush:
  3091. if ( tr.fraction == 1.0f )
  3092. return; // Explicitly end
  3093. default:
  3094. // By default, no collision
  3095. tr.fraction = 1.0f;
  3096. break;
  3097. }
  3098. }
  3099. switch ( modelType )
  3100. {
  3101. case mod_studio:
  3102. AddColoredStudioDecal( ray, hitbox, decalIndex, doTrace, tr, cColor, maxLODToDecal );
  3103. break;
  3104. case mod_brush:
  3105. {
  3106. color32 cColor32 = { cColor.r(), cColor.g(), cColor.b(), cColor.a() };
  3107. effects->DecalColorShoot( decalIndex, index, model, GetAbsOrigin(), GetAbsAngles(), decalCenter, 0, 0, cColor32 );
  3108. }
  3109. break;
  3110. default:
  3111. // By default, no collision
  3112. tr.fraction = 1.0f;
  3113. break;
  3114. }
  3115. }
  3116. //-----------------------------------------------------------------------------
  3117. // A method to remove all decals from an entity
  3118. //-----------------------------------------------------------------------------
  3119. void C_BaseEntity::RemoveAllDecals( void )
  3120. {
  3121. // For now, we only handle removing decals from studiomodels
  3122. if ( modelinfo->GetModelType( model ) == mod_studio )
  3123. {
  3124. CreateModelInstance();
  3125. modelrender->RemoveAllDecals( m_ModelInstance );
  3126. }
  3127. }
  3128. bool C_BaseEntity::SnatchModelInstance( C_BaseEntity *pToEntity )
  3129. {
  3130. if ( !modelrender->ChangeInstance( GetModelInstance(), pToEntity ) )
  3131. return false; // engine could move modle handle
  3132. // remove old handle from toentity if any
  3133. if ( pToEntity->GetModelInstance() != MODEL_INSTANCE_INVALID )
  3134. pToEntity->DestroyModelInstance();
  3135. // move the handle to other entity
  3136. pToEntity->SetModelInstance( GetModelInstance() );
  3137. // delete own reference
  3138. SetModelInstance( MODEL_INSTANCE_INVALID );
  3139. return true;
  3140. }
  3141. #include "tier0/memdbgoff.h"
  3142. //-----------------------------------------------------------------------------
  3143. // C_BaseEntity new/delete
  3144. // All fields in the object are all initialized to 0.
  3145. //-----------------------------------------------------------------------------
  3146. void *C_BaseEntity::operator new( size_t stAllocateBlock )
  3147. {
  3148. Assert( stAllocateBlock != 0 );
  3149. MEM_ALLOC_CREDIT();
  3150. void *pMem = MemAlloc_Alloc( stAllocateBlock );
  3151. memset( pMem, 0, stAllocateBlock );
  3152. return pMem;
  3153. }
  3154. void *C_BaseEntity::operator new[]( size_t stAllocateBlock )
  3155. {
  3156. Assert( stAllocateBlock != 0 );
  3157. MEM_ALLOC_CREDIT();
  3158. void *pMem = MemAlloc_Alloc( stAllocateBlock );
  3159. memset( pMem, 0, stAllocateBlock );
  3160. return pMem;
  3161. }
  3162. void *C_BaseEntity::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
  3163. {
  3164. Assert( stAllocateBlock != 0 );
  3165. void *pMem = MemAlloc_Alloc( stAllocateBlock, pFileName, nLine );
  3166. memset( pMem, 0, stAllocateBlock );
  3167. return pMem;
  3168. }
  3169. void *C_BaseEntity::operator new[]( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
  3170. {
  3171. Assert( stAllocateBlock != 0 );
  3172. void *pMem = MemAlloc_Alloc( stAllocateBlock, pFileName, nLine );
  3173. memset( pMem, 0, stAllocateBlock );
  3174. return pMem;
  3175. }
  3176. //-----------------------------------------------------------------------------
  3177. // Purpose:
  3178. // Input : *pMem -
  3179. //-----------------------------------------------------------------------------
  3180. void C_BaseEntity::operator delete( void *pMem )
  3181. {
  3182. // get the engine to free the memory
  3183. MemAlloc_Free( pMem );
  3184. }
  3185. #include "tier0/memdbgon.h"
  3186. //========================================================================================
  3187. // TEAM HANDLING
  3188. //========================================================================================
  3189. C_Team *C_BaseEntity::GetTeam( void )
  3190. {
  3191. return GetGlobalTeam( m_iTeamNum );
  3192. }
  3193. //-----------------------------------------------------------------------------
  3194. // Purpose:
  3195. // Output : int
  3196. //-----------------------------------------------------------------------------
  3197. int C_BaseEntity::GetTeamNumber( void ) const
  3198. {
  3199. return m_iTeamNum;
  3200. }
  3201. //-----------------------------------------------------------------------------
  3202. // Purpose:
  3203. //-----------------------------------------------------------------------------
  3204. int C_BaseEntity::GetRenderTeamNumber( void )
  3205. {
  3206. return GetTeamNumber();
  3207. }
  3208. //-----------------------------------------------------------------------------
  3209. // Purpose: Returns true if these entities are both in at least one team together
  3210. //-----------------------------------------------------------------------------
  3211. bool C_BaseEntity::InSameTeam( C_BaseEntity *pEntity )
  3212. {
  3213. if ( !pEntity )
  3214. return false;
  3215. return ( pEntity->GetTeam() == GetTeam() );
  3216. }
  3217. //-----------------------------------------------------------------------------
  3218. // Purpose: Returns true if the entity's on the same team as the local player
  3219. //-----------------------------------------------------------------------------
  3220. bool C_BaseEntity::InLocalTeam( void )
  3221. {
  3222. return ( GetTeam() == GetLocalTeam() );
  3223. }
  3224. void C_BaseEntity::SetNextClientThink( float nextThinkTime )
  3225. {
  3226. Assert( GetClientHandle() != INVALID_CLIENTENTITY_HANDLE );
  3227. ClientThinkList()->SetNextClientThink( GetClientHandle(), nextThinkTime );
  3228. }
  3229. void C_BaseEntity::AddToLeafSystem()
  3230. {
  3231. AddToLeafSystem( GetRenderGroup() );
  3232. }
  3233. void C_BaseEntity::AddToLeafSystem( RenderGroup_t group )
  3234. {
  3235. if( m_hRender == INVALID_CLIENT_RENDER_HANDLE )
  3236. {
  3237. // create new renderer handle
  3238. ClientLeafSystem()->AddRenderable( this, group );
  3239. ClientLeafSystem()->EnableAlternateSorting( m_hRender, m_bAlternateSorting );
  3240. }
  3241. else
  3242. {
  3243. // handle already exists, just update group & origin
  3244. ClientLeafSystem()->SetRenderGroup( m_hRender, group );
  3245. ClientLeafSystem()->RenderableChanged( m_hRender );
  3246. }
  3247. }
  3248. //-----------------------------------------------------------------------------
  3249. // Creates the shadow (if it doesn't already exist) based on shadow cast type
  3250. //-----------------------------------------------------------------------------
  3251. void C_BaseEntity::CreateShadow()
  3252. {
  3253. ShadowType_t shadowType = ShadowCastType();
  3254. if (shadowType == SHADOWS_NONE)
  3255. {
  3256. DestroyShadow();
  3257. }
  3258. else
  3259. {
  3260. if (m_ShadowHandle == CLIENTSHADOW_INVALID_HANDLE)
  3261. {
  3262. int flags = SHADOW_FLAGS_SHADOW;
  3263. if (shadowType != SHADOWS_SIMPLE)
  3264. flags |= SHADOW_FLAGS_USE_RENDER_TO_TEXTURE;
  3265. if (shadowType == SHADOWS_RENDER_TO_TEXTURE_DYNAMIC)
  3266. flags |= SHADOW_FLAGS_ANIMATING_SOURCE;
  3267. m_ShadowHandle = g_pClientShadowMgr->CreateShadow(GetClientHandle(), flags);
  3268. }
  3269. }
  3270. }
  3271. //-----------------------------------------------------------------------------
  3272. // Removes the shadow
  3273. //-----------------------------------------------------------------------------
  3274. void C_BaseEntity::DestroyShadow()
  3275. {
  3276. // NOTE: This will actually cause the shadow type to be recomputed
  3277. // if the entity doesn't immediately go away
  3278. if (m_ShadowHandle != CLIENTSHADOW_INVALID_HANDLE)
  3279. {
  3280. g_pClientShadowMgr->DestroyShadow(m_ShadowHandle);
  3281. m_ShadowHandle = CLIENTSHADOW_INVALID_HANDLE;
  3282. }
  3283. }
  3284. //-----------------------------------------------------------------------------
  3285. // Removes the entity from the leaf system
  3286. //-----------------------------------------------------------------------------
  3287. void C_BaseEntity::RemoveFromLeafSystem()
  3288. {
  3289. // Detach from the leaf lists.
  3290. if( m_hRender != INVALID_CLIENT_RENDER_HANDLE )
  3291. {
  3292. ClientLeafSystem()->RemoveRenderable( m_hRender );
  3293. m_hRender = INVALID_CLIENT_RENDER_HANDLE;
  3294. }
  3295. DestroyShadow();
  3296. }
  3297. //-----------------------------------------------------------------------------
  3298. // Purpose: Flags this entity as being inside or outside of this client's PVS
  3299. // on the server.
  3300. // NOTE: this is meaningless for client-side only entities.
  3301. // Input : inside_pvs -
  3302. //-----------------------------------------------------------------------------
  3303. void C_BaseEntity::SetDormant( bool bDormant )
  3304. {
  3305. Assert( IsServerEntity() );
  3306. m_bDormant = bDormant;
  3307. // Kill drawing if we became dormant.
  3308. UpdateVisibility();
  3309. ParticleProp()->OwnerSetDormantTo( bDormant );
  3310. }
  3311. //-----------------------------------------------------------------------------
  3312. // Purpose: Returns whether this entity is dormant. Client/server entities become
  3313. // dormant when they leave the PVS on the server. Client side entities
  3314. // can decide for themselves whether to become dormant.
  3315. //-----------------------------------------------------------------------------
  3316. bool C_BaseEntity::IsDormant( void )
  3317. {
  3318. if ( IsServerEntity() )
  3319. {
  3320. return m_bDormant;
  3321. }
  3322. return false;
  3323. }
  3324. //-----------------------------------------------------------------------------
  3325. // Purpose: Tells the entity that it's about to be destroyed due to the client receiving
  3326. // an uncompressed update that's caused it to destroy all entities & recreate them.
  3327. //-----------------------------------------------------------------------------
  3328. void C_BaseEntity::SetDestroyedOnRecreateEntities( void )
  3329. {
  3330. // Robin: We need to destroy all our particle systems immediately, because
  3331. // we're about to be recreated, and their owner EHANDLEs will match up to
  3332. // the new entity, but it won't know anything about them.
  3333. ParticleProp()->StopEmissionAndDestroyImmediately();
  3334. }
  3335. //-----------------------------------------------------------------------------
  3336. // These methods recompute local versions as well as set abs versions
  3337. //-----------------------------------------------------------------------------
  3338. void C_BaseEntity::SetAbsOrigin( const Vector& absOrigin )
  3339. {
  3340. // This is necessary to get the other fields of m_rgflCoordinateFrame ok
  3341. CalcAbsolutePosition();
  3342. if ( m_vecAbsOrigin == absOrigin )
  3343. return;
  3344. // All children are invalid, but we are not
  3345. InvalidatePhysicsRecursive( POSITION_CHANGED );
  3346. RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
  3347. m_vecAbsOrigin = absOrigin;
  3348. MatrixSetColumn( absOrigin, 3, m_rgflCoordinateFrame );
  3349. C_BaseEntity *pMoveParent = GetMoveParent();
  3350. if (!pMoveParent)
  3351. {
  3352. m_vecOrigin = absOrigin;
  3353. return;
  3354. }
  3355. // Moveparent case: transform the abs position into local space
  3356. VectorITransform( absOrigin, pMoveParent->EntityToWorldTransform(), (Vector&)m_vecOrigin );
  3357. }
  3358. void C_BaseEntity::SetAbsAngles( const QAngle& absAngles )
  3359. {
  3360. // This is necessary to get the other fields of m_rgflCoordinateFrame ok
  3361. CalcAbsolutePosition();
  3362. // FIXME: The normalize caused problems in server code like momentary_rot_button that isn't
  3363. // handling things like +/-180 degrees properly. This should be revisited.
  3364. //QAngle angleNormalize( AngleNormalize( absAngles.x ), AngleNormalize( absAngles.y ), AngleNormalize( absAngles.z ) );
  3365. if ( m_angAbsRotation == absAngles )
  3366. return;
  3367. InvalidatePhysicsRecursive( ANGLES_CHANGED );
  3368. RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
  3369. m_angAbsRotation = absAngles;
  3370. AngleMatrix( absAngles, m_rgflCoordinateFrame );
  3371. MatrixSetColumn( m_vecAbsOrigin, 3, m_rgflCoordinateFrame );
  3372. C_BaseEntity *pMoveParent = GetMoveParent();
  3373. if (!pMoveParent)
  3374. {
  3375. m_angRotation = absAngles;
  3376. return;
  3377. }
  3378. // Moveparent case: we're aligned with the move parent
  3379. if ( m_angAbsRotation == pMoveParent->GetAbsAngles() )
  3380. {
  3381. m_angRotation.Init( );
  3382. }
  3383. else
  3384. {
  3385. // Moveparent case: transform the abs transform into local space
  3386. matrix3x4_t worldToParent, localMatrix;
  3387. MatrixInvert( pMoveParent->EntityToWorldTransform(), worldToParent );
  3388. ConcatTransforms( worldToParent, m_rgflCoordinateFrame, localMatrix );
  3389. MatrixAngles( localMatrix, (QAngle &)m_angRotation );
  3390. }
  3391. }
  3392. void C_BaseEntity::SetAbsVelocity( const Vector &vecAbsVelocity )
  3393. {
  3394. if ( m_vecAbsVelocity == vecAbsVelocity )
  3395. return;
  3396. // The abs velocity won't be dirty since we're setting it here
  3397. InvalidatePhysicsRecursive( VELOCITY_CHANGED );
  3398. m_iEFlags &= ~EFL_DIRTY_ABSVELOCITY;
  3399. m_vecAbsVelocity = vecAbsVelocity;
  3400. C_BaseEntity *pMoveParent = GetMoveParent();
  3401. if (!pMoveParent)
  3402. {
  3403. m_vecVelocity = vecAbsVelocity;
  3404. return;
  3405. }
  3406. // First subtract out the parent's abs velocity to get a relative
  3407. // velocity measured in world space
  3408. Vector relVelocity;
  3409. VectorSubtract( vecAbsVelocity, pMoveParent->GetAbsVelocity(), relVelocity );
  3410. // Transform velocity into parent space
  3411. VectorIRotate( relVelocity, pMoveParent->EntityToWorldTransform(), m_vecVelocity );
  3412. }
  3413. /*
  3414. void C_BaseEntity::SetAbsAngularVelocity( const QAngle &vecAbsAngVelocity )
  3415. {
  3416. // The abs velocity won't be dirty since we're setting it here
  3417. InvalidatePhysicsRecursive( EFL_DIRTY_ABSANGVELOCITY );
  3418. m_iEFlags &= ~EFL_DIRTY_ABSANGVELOCITY;
  3419. m_vecAbsAngVelocity = vecAbsAngVelocity;
  3420. C_BaseEntity *pMoveParent = GetMoveParent();
  3421. if (!pMoveParent)
  3422. {
  3423. m_vecAngVelocity = vecAbsAngVelocity;
  3424. return;
  3425. }
  3426. // First subtract out the parent's abs velocity to get a relative
  3427. // angular velocity measured in world space
  3428. QAngle relAngVelocity;
  3429. relAngVelocity = vecAbsAngVelocity - pMoveParent->GetAbsAngularVelocity();
  3430. matrix3x4_t entityToWorld;
  3431. AngleMatrix( relAngVelocity, entityToWorld );
  3432. // Moveparent case: transform the abs angular vel into local space
  3433. matrix3x4_t worldToParent, localMatrix;
  3434. MatrixInvert( pMoveParent->EntityToWorldTransform(), worldToParent );
  3435. ConcatTransforms( worldToParent, entityToWorld, localMatrix );
  3436. MatrixAngles( localMatrix, m_vecAngVelocity );
  3437. }
  3438. */
  3439. // Prevent these for now until hierarchy is properly networked
  3440. const Vector& C_BaseEntity::GetLocalOrigin( void ) const
  3441. {
  3442. return m_vecOrigin;
  3443. }
  3444. vec_t C_BaseEntity::GetLocalOriginDim( int iDim ) const
  3445. {
  3446. return m_vecOrigin[iDim];
  3447. }
  3448. // Prevent these for now until hierarchy is properly networked
  3449. void C_BaseEntity::SetLocalOrigin( const Vector& origin )
  3450. {
  3451. if (m_vecOrigin != origin)
  3452. {
  3453. InvalidatePhysicsRecursive( POSITION_CHANGED );
  3454. m_vecOrigin = origin;
  3455. }
  3456. }
  3457. void C_BaseEntity::SetLocalOriginDim( int iDim, vec_t flValue )
  3458. {
  3459. if (m_vecOrigin[iDim] != flValue)
  3460. {
  3461. InvalidatePhysicsRecursive( POSITION_CHANGED );
  3462. m_vecOrigin[iDim] = flValue;
  3463. }
  3464. }
  3465. // Prevent these for now until hierarchy is properly networked
  3466. const QAngle& C_BaseEntity::GetLocalAngles( void ) const
  3467. {
  3468. return m_angRotation;
  3469. }
  3470. vec_t C_BaseEntity::GetLocalAnglesDim( int iDim ) const
  3471. {
  3472. return m_angRotation[iDim];
  3473. }
  3474. // Prevent these for now until hierarchy is properly networked
  3475. void C_BaseEntity::SetLocalAngles( const QAngle& angles )
  3476. {
  3477. // NOTE: The angle normalize is a little expensive, but we can save
  3478. // a bunch of time in interpolation if we don't have to invalidate everything
  3479. // and sometimes it's off by a normalization amount
  3480. // FIXME: The normalize caused problems in server code like momentary_rot_button that isn't
  3481. // handling things like +/-180 degrees properly. This should be revisited.
  3482. //QAngle angleNormalize( AngleNormalize( angles.x ), AngleNormalize( angles.y ), AngleNormalize( angles.z ) );
  3483. if (m_angRotation != angles)
  3484. {
  3485. // This will cause the velocities of all children to need recomputation
  3486. InvalidatePhysicsRecursive( ANGLES_CHANGED );
  3487. m_angRotation = angles;
  3488. }
  3489. }
  3490. void C_BaseEntity::SetLocalAnglesDim( int iDim, vec_t flValue )
  3491. {
  3492. flValue = AngleNormalize( flValue );
  3493. if (m_angRotation[iDim] != flValue)
  3494. {
  3495. // This will cause the velocities of all children to need recomputation
  3496. InvalidatePhysicsRecursive( ANGLES_CHANGED );
  3497. m_angRotation[iDim] = flValue;
  3498. }
  3499. }
  3500. void C_BaseEntity::SetLocalVelocity( const Vector &vecVelocity )
  3501. {
  3502. if (m_vecVelocity != vecVelocity)
  3503. {
  3504. InvalidatePhysicsRecursive( VELOCITY_CHANGED );
  3505. m_vecVelocity = vecVelocity;
  3506. }
  3507. }
  3508. void C_BaseEntity::SetLocalAngularVelocity( const QAngle &vecAngVelocity )
  3509. {
  3510. if (m_vecAngVelocity != vecAngVelocity)
  3511. {
  3512. // InvalidatePhysicsRecursive( ANG_VELOCITY_CHANGED );
  3513. m_vecAngVelocity = vecAngVelocity;
  3514. }
  3515. }
  3516. //-----------------------------------------------------------------------------
  3517. // Sets the local position from a transform
  3518. //-----------------------------------------------------------------------------
  3519. void C_BaseEntity::SetLocalTransform( const matrix3x4_t &localTransform )
  3520. {
  3521. Vector vecLocalOrigin;
  3522. QAngle vecLocalAngles;
  3523. MatrixGetColumn( localTransform, 3, vecLocalOrigin );
  3524. MatrixAngles( localTransform, vecLocalAngles );
  3525. SetLocalOrigin( vecLocalOrigin );
  3526. SetLocalAngles( vecLocalAngles );
  3527. }
  3528. //-----------------------------------------------------------------------------
  3529. // FIXME: REMOVE!!!
  3530. //-----------------------------------------------------------------------------
  3531. void C_BaseEntity::MoveToAimEnt( )
  3532. {
  3533. Vector vecAimEntOrigin;
  3534. QAngle vecAimEntAngles;
  3535. GetAimEntOrigin( GetMoveParent(), &vecAimEntOrigin, &vecAimEntAngles );
  3536. SetAbsOrigin( vecAimEntOrigin );
  3537. SetAbsAngles( vecAimEntAngles );
  3538. }
  3539. void C_BaseEntity::BoneMergeFastCullBloat( Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs ) const
  3540. {
  3541. // By default, we bloat the bbox for fastcull ents by the maximum length it could hang out of the parent bbox,
  3542. // it one corner were touching the edge of the parent's box, and the whole diagonal stretched out.
  3543. float flExpand = (thisEntityMaxs - thisEntityMins).Length();
  3544. localMins.x -= flExpand;
  3545. localMins.y -= flExpand;
  3546. localMins.z -= flExpand;
  3547. localMaxs.x += flExpand;
  3548. localMaxs.y += flExpand;
  3549. localMaxs.z += flExpand;
  3550. }
  3551. matrix3x4_t& C_BaseEntity::GetParentToWorldTransform( matrix3x4_t &tempMatrix )
  3552. {
  3553. CBaseEntity *pMoveParent = GetMoveParent();
  3554. if ( !pMoveParent )
  3555. {
  3556. Assert( false );
  3557. SetIdentityMatrix( tempMatrix );
  3558. return tempMatrix;
  3559. }
  3560. if ( m_iParentAttachment != 0 )
  3561. {
  3562. Vector vOrigin;
  3563. QAngle vAngles;
  3564. if ( pMoveParent->GetAttachment( m_iParentAttachment, vOrigin, vAngles ) )
  3565. {
  3566. AngleMatrix( vAngles, vOrigin, tempMatrix );
  3567. return tempMatrix;
  3568. }
  3569. }
  3570. // If we fall through to here, then just use the move parent's abs origin and angles.
  3571. return pMoveParent->EntityToWorldTransform();
  3572. }
  3573. //-----------------------------------------------------------------------------
  3574. // Purpose: Calculates the absolute position of an edict in the world
  3575. // assumes the parent's absolute origin has already been calculated
  3576. //-----------------------------------------------------------------------------
  3577. void C_BaseEntity::CalcAbsolutePosition( )
  3578. {
  3579. // There are periods of time where we're gonna have to live with the
  3580. // fact that we're in an indeterminant state and abs queries (which
  3581. // shouldn't be happening at all; I have assertions for those), will
  3582. // just have to accept stale data.
  3583. if (!s_bAbsRecomputationEnabled)
  3584. return;
  3585. // FIXME: Recompute absbox!!!
  3586. if ((m_iEFlags & EFL_DIRTY_ABSTRANSFORM) == 0)
  3587. {
  3588. // quick check to make sure we really don't need an update
  3589. // Assert( m_pMoveParent || m_vecAbsOrigin == GetLocalOrigin() );
  3590. return;
  3591. }
  3592. AUTO_LOCK( m_CalcAbsolutePositionMutex );
  3593. if ((m_iEFlags & EFL_DIRTY_ABSTRANSFORM) == 0) // need second check in event another thread grabbed mutex and did the calculation
  3594. {
  3595. return;
  3596. }
  3597. RemoveEFlags( EFL_DIRTY_ABSTRANSFORM );
  3598. if (!m_pMoveParent)
  3599. {
  3600. // Construct the entity-to-world matrix
  3601. // Start with making an entity-to-parent matrix
  3602. AngleMatrix( GetLocalAngles(), GetLocalOrigin(), m_rgflCoordinateFrame );
  3603. m_vecAbsOrigin = GetLocalOrigin();
  3604. m_angAbsRotation = GetLocalAngles();
  3605. NormalizeAngles( m_angAbsRotation );
  3606. return;
  3607. }
  3608. if ( IsEffectActive(EF_BONEMERGE) )
  3609. {
  3610. MoveToAimEnt();
  3611. return;
  3612. }
  3613. // Construct the entity-to-world matrix
  3614. // Start with making an entity-to-parent matrix
  3615. matrix3x4_t matEntityToParent;
  3616. AngleMatrix( GetLocalAngles(), matEntityToParent );
  3617. MatrixSetColumn( GetLocalOrigin(), 3, matEntityToParent );
  3618. // concatenate with our parent's transform
  3619. matrix3x4_t scratchMatrix;
  3620. ConcatTransforms( GetParentToWorldTransform( scratchMatrix ), matEntityToParent, m_rgflCoordinateFrame );
  3621. // pull our absolute position out of the matrix
  3622. MatrixGetColumn( m_rgflCoordinateFrame, 3, m_vecAbsOrigin );
  3623. // if we have any angles, we have to extract our absolute angles from our matrix
  3624. if ( m_angRotation == vec3_angle && m_iParentAttachment == 0 )
  3625. {
  3626. // just copy our parent's absolute angles
  3627. VectorCopy( m_pMoveParent->GetAbsAngles(), m_angAbsRotation );
  3628. }
  3629. else
  3630. {
  3631. MatrixAngles( m_rgflCoordinateFrame, m_angAbsRotation );
  3632. }
  3633. // This is necessary because it's possible that our moveparent's CalculateIKLocks will trigger its move children
  3634. // (ie: this entity) to call GetAbsOrigin(), and they'll use the moveparent's OLD bone transforms to get their attachments
  3635. // since the moveparent is right in the middle of setting up new transforms.
  3636. //
  3637. // So here, we keep our absorigin invalidated. It means we're returning an origin that is a frame old to CalculateIKLocks,
  3638. // but we'll still render with the right origin.
  3639. if ( m_iParentAttachment != 0 && (m_pMoveParent->GetEFlags() & EFL_SETTING_UP_BONES) )
  3640. {
  3641. m_iEFlags |= EFL_DIRTY_ABSTRANSFORM;
  3642. }
  3643. }
  3644. void C_BaseEntity::CalcAbsoluteVelocity()
  3645. {
  3646. if ((m_iEFlags & EFL_DIRTY_ABSVELOCITY ) == 0)
  3647. return;
  3648. AUTO_LOCK( m_CalcAbsoluteVelocityMutex );
  3649. if ((m_iEFlags & EFL_DIRTY_ABSVELOCITY) == 0) // need second check in event another thread grabbed mutex and did the calculation
  3650. {
  3651. return;
  3652. }
  3653. m_iEFlags &= ~EFL_DIRTY_ABSVELOCITY;
  3654. CBaseEntity *pMoveParent = GetMoveParent();
  3655. if ( !pMoveParent )
  3656. {
  3657. m_vecAbsVelocity = m_vecVelocity;
  3658. return;
  3659. }
  3660. VectorRotate( m_vecVelocity, pMoveParent->EntityToWorldTransform(), m_vecAbsVelocity );
  3661. // Add in the attachments velocity if it exists
  3662. if ( m_iParentAttachment != 0 )
  3663. {
  3664. Vector vOriginVel;
  3665. Quaternion vAngleVel;
  3666. if ( pMoveParent->GetAttachmentVelocity( m_iParentAttachment, vOriginVel, vAngleVel ) )
  3667. {
  3668. m_vecAbsVelocity += vOriginVel;
  3669. return;
  3670. }
  3671. }
  3672. // Now add in the parent abs velocity
  3673. m_vecAbsVelocity += pMoveParent->GetAbsVelocity();
  3674. }
  3675. /*
  3676. void C_BaseEntity::CalcAbsoluteAngularVelocity()
  3677. {
  3678. if ((m_iEFlags & EFL_DIRTY_ABSANGVELOCITY ) == 0)
  3679. return;
  3680. m_iEFlags &= ~EFL_DIRTY_ABSANGVELOCITY;
  3681. CBaseEntity *pMoveParent = GetMoveParent();
  3682. if ( !pMoveParent )
  3683. {
  3684. m_vecAbsAngVelocity = m_vecAngVelocity;
  3685. return;
  3686. }
  3687. matrix3x4_t angVelToParent, angVelToWorld;
  3688. AngleMatrix( m_vecAngVelocity, angVelToParent );
  3689. ConcatTransforms( pMoveParent->EntityToWorldTransform(), angVelToParent, angVelToWorld );
  3690. MatrixAngles( angVelToWorld, m_vecAbsAngVelocity );
  3691. // Now add in the parent abs angular velocity
  3692. m_vecAbsAngVelocity += pMoveParent->GetAbsAngularVelocity();
  3693. }
  3694. */
  3695. //-----------------------------------------------------------------------------
  3696. // Computes the abs position of a point specified in local space
  3697. //-----------------------------------------------------------------------------
  3698. void C_BaseEntity::ComputeAbsPosition( const Vector &vecLocalPosition, Vector *pAbsPosition )
  3699. {
  3700. C_BaseEntity *pMoveParent = GetMoveParent();
  3701. if ( !pMoveParent )
  3702. {
  3703. *pAbsPosition = vecLocalPosition;
  3704. }
  3705. else
  3706. {
  3707. VectorTransform( vecLocalPosition, pMoveParent->EntityToWorldTransform(), *pAbsPosition );
  3708. }
  3709. }
  3710. //-----------------------------------------------------------------------------
  3711. // Computes the abs position of a point specified in local space
  3712. //-----------------------------------------------------------------------------
  3713. void C_BaseEntity::ComputeAbsDirection( const Vector &vecLocalDirection, Vector *pAbsDirection )
  3714. {
  3715. C_BaseEntity *pMoveParent = GetMoveParent();
  3716. if ( !pMoveParent )
  3717. {
  3718. *pAbsDirection = vecLocalDirection;
  3719. }
  3720. else
  3721. {
  3722. VectorRotate( vecLocalDirection, pMoveParent->EntityToWorldTransform(), *pAbsDirection );
  3723. }
  3724. }
  3725. //-----------------------------------------------------------------------------
  3726. // Mark shadow as dirty
  3727. //-----------------------------------------------------------------------------
  3728. void C_BaseEntity::MarkRenderHandleDirty( )
  3729. {
  3730. // Invalidate render leaf too
  3731. ClientRenderHandle_t handle = GetRenderHandle();
  3732. if ( handle != INVALID_CLIENT_RENDER_HANDLE )
  3733. {
  3734. ClientLeafSystem()->RenderableChanged( handle );
  3735. }
  3736. }
  3737. //-----------------------------------------------------------------------------
  3738. // Purpose:
  3739. //-----------------------------------------------------------------------------
  3740. void C_BaseEntity::ShutdownPredictable( void )
  3741. {
  3742. #if !defined( NO_ENTITY_PREDICTION )
  3743. Assert( GetPredictable() );
  3744. g_Predictables.RemoveFromPredictablesList( GetClientHandle() );
  3745. DestroyIntermediateData();
  3746. SetPredictable( false );
  3747. #endif
  3748. }
  3749. //-----------------------------------------------------------------------------
  3750. // Purpose: Turn entity into something the predicts locally
  3751. //-----------------------------------------------------------------------------
  3752. void C_BaseEntity::InitPredictable( void )
  3753. {
  3754. #if !defined( NO_ENTITY_PREDICTION )
  3755. Assert( !GetPredictable() );
  3756. // Mark as predictable
  3757. SetPredictable( true );
  3758. // Allocate buffers into which we copy data
  3759. AllocateIntermediateData();
  3760. // Add to list of predictables
  3761. g_Predictables.AddToPredictableList( GetClientHandle() );
  3762. // Copy everything from "this" into the original_state_data
  3763. // object. Don't care about client local stuff, so pull from slot 0 which
  3764. // should be empty anyway...
  3765. PostNetworkDataReceived( 0 );
  3766. // Copy original data into all prediction slots, so we don't get an error saying we "mispredicted" any
  3767. // values which are still at their initial values
  3768. for ( int i = 0; i < MULTIPLAYER_BACKUP; i++ )
  3769. {
  3770. SaveData( "InitPredictable", i, PC_EVERYTHING );
  3771. }
  3772. #endif
  3773. }
  3774. //-----------------------------------------------------------------------------
  3775. // Purpose:
  3776. // Input : state -
  3777. //-----------------------------------------------------------------------------
  3778. void C_BaseEntity::SetPredictable( bool state )
  3779. {
  3780. m_bPredictable = state;
  3781. // update interpolation times
  3782. Interp_UpdateInterpolationAmounts( GetVarMapping() );
  3783. }
  3784. //-----------------------------------------------------------------------------
  3785. // Purpose:
  3786. // Output : Returns true on success, false on failure.
  3787. //-----------------------------------------------------------------------------
  3788. bool C_BaseEntity::GetPredictable( void ) const
  3789. {
  3790. return m_bPredictable;
  3791. }
  3792. //-----------------------------------------------------------------------------
  3793. // Purpose: Transfer data for intermediate frame to current entity
  3794. // Input : copyintermediate -
  3795. // last_predicted -
  3796. //-----------------------------------------------------------------------------
  3797. void C_BaseEntity::PreEntityPacketReceived( int commands_acknowledged )
  3798. {
  3799. #if !defined( NO_ENTITY_PREDICTION )
  3800. // Don't need to copy intermediate data if server did ack any new commands
  3801. bool copyintermediate = ( commands_acknowledged > 0 ) ? true : false;
  3802. Assert( GetPredictable() );
  3803. Assert( cl_predict->GetInt() );
  3804. // First copy in any intermediate predicted data for non-networked fields
  3805. if ( copyintermediate )
  3806. {
  3807. RestoreData( "PreEntityPacketReceived", commands_acknowledged - 1, PC_NON_NETWORKED_ONLY );
  3808. RestoreData( "PreEntityPacketReceived", SLOT_ORIGINALDATA, PC_NETWORKED_ONLY );
  3809. }
  3810. else
  3811. {
  3812. RestoreData( "PreEntityPacketReceived(no commands ack)", SLOT_ORIGINALDATA, PC_EVERYTHING );
  3813. }
  3814. // At this point the entity has original network data restored as of the last time the
  3815. // networking was updated, and it has any intermediate predicted values properly copied over
  3816. // Unpacked and OnDataChanged will fill in any changed, networked fields.
  3817. // That networked data will be copied forward into the starting slot for the next prediction round
  3818. #endif
  3819. }
  3820. //-----------------------------------------------------------------------------
  3821. // Purpose: Called every time PreEntityPacket received is called
  3822. // copy any networked data into original_state
  3823. // Input : errorcheck -
  3824. // last_predicted -
  3825. //-----------------------------------------------------------------------------
  3826. void C_BaseEntity::PostEntityPacketReceived( void )
  3827. {
  3828. #if !defined( NO_ENTITY_PREDICTION )
  3829. Assert( GetPredictable() );
  3830. Assert( cl_predict->GetInt() );
  3831. // Always mark as changed
  3832. AddDataChangeEvent( this, DATA_UPDATE_DATATABLE_CHANGED, &m_DataChangeEventRef );
  3833. // Save networked fields into "original data" store
  3834. SaveData( "PostEntityPacketReceived", SLOT_ORIGINALDATA, PC_NETWORKED_ONLY );
  3835. #endif
  3836. }
  3837. //-----------------------------------------------------------------------------
  3838. // Purpose: Called once per frame after all updating is done
  3839. // Input : errorcheck -
  3840. // last_predicted -
  3841. //-----------------------------------------------------------------------------
  3842. bool C_BaseEntity::PostNetworkDataReceived( int commands_acknowledged )
  3843. {
  3844. bool haderrors = false;
  3845. #if !defined( NO_ENTITY_PREDICTION )
  3846. Assert( GetPredictable() );
  3847. bool errorcheck = ( commands_acknowledged > 0 ) ? true : false;
  3848. // Store network data into post networking pristine state slot (slot 64)
  3849. SaveData( "PostNetworkDataReceived", SLOT_ORIGINALDATA, PC_EVERYTHING );
  3850. // Show any networked fields that are different
  3851. bool showthis = cl_showerror.GetInt() >= 2;
  3852. if ( cl_showerror.GetInt() < 0 )
  3853. {
  3854. if ( entindex() == -cl_showerror.GetInt() )
  3855. {
  3856. showthis = true;
  3857. }
  3858. else
  3859. {
  3860. showthis = false;
  3861. }
  3862. }
  3863. if ( errorcheck )
  3864. {
  3865. void *predicted_state_data = GetPredictedFrame( commands_acknowledged - 1 );
  3866. Assert( predicted_state_data );
  3867. const void *original_state_data = GetOriginalNetworkDataObject();
  3868. Assert( original_state_data );
  3869. bool counterrors = true;
  3870. bool reporterrors = showthis;
  3871. bool copydata = false;
  3872. CPredictionCopy errorCheckHelper( PC_NETWORKED_ONLY,
  3873. predicted_state_data, PC_DATA_PACKED,
  3874. original_state_data, PC_DATA_PACKED,
  3875. counterrors, reporterrors, copydata );
  3876. // Suppress debugging output
  3877. int ecount = errorCheckHelper.TransferData( "", -1, GetPredDescMap() );
  3878. if ( ecount > 0 )
  3879. {
  3880. haderrors = true;
  3881. // Msg( "%i errors %i on entity %i %s\n", gpGlobals->tickcount, ecount, index, IsClientCreated() ? "true" : "false" );
  3882. }
  3883. }
  3884. #endif
  3885. return haderrors;
  3886. }
  3887. // Stuff implemented for weapon prediction code
  3888. void C_BaseEntity::SetSize( const Vector &vecMin, const Vector &vecMax )
  3889. {
  3890. SetCollisionBounds( vecMin, vecMax );
  3891. }
  3892. //-----------------------------------------------------------------------------
  3893. // Purpose: Just look up index
  3894. // Input : *name -
  3895. // Output : int
  3896. //-----------------------------------------------------------------------------
  3897. int C_BaseEntity::PrecacheModel( const char *name )
  3898. {
  3899. return modelinfo->GetModelIndex( name );
  3900. }
  3901. //-----------------------------------------------------------------------------
  3902. // Purpose:
  3903. // Input : *obj -
  3904. //-----------------------------------------------------------------------------
  3905. void C_BaseEntity::Remove( )
  3906. {
  3907. // Nothing for now, if it's a predicted entity, could flag as "delete" or dormant
  3908. if ( GetPredictable() || IsClientCreated() )
  3909. {
  3910. // Make it solid
  3911. AddSolidFlags( FSOLID_NOT_SOLID );
  3912. SetMoveType( MOVETYPE_NONE );
  3913. AddEFlags( EFL_KILLME ); // Make sure to ignore further calls into here or UTIL_Remove.
  3914. }
  3915. Release();
  3916. }
  3917. //-----------------------------------------------------------------------------
  3918. // Purpose:
  3919. // Output : Returns true on success, false on failure.
  3920. //-----------------------------------------------------------------------------
  3921. bool C_BaseEntity::GetPredictionEligible( void ) const
  3922. {
  3923. #if !defined( NO_ENTITY_PREDICTION )
  3924. return m_bPredictionEligible;
  3925. #else
  3926. return false;
  3927. #endif
  3928. }
  3929. C_BaseEntity* C_BaseEntity::Instance( CBaseHandle hEnt )
  3930. {
  3931. return ClientEntityList().GetBaseEntityFromHandle( hEnt );
  3932. }
  3933. //-----------------------------------------------------------------------------
  3934. // Purpose:
  3935. // Input : iEnt -
  3936. // Output : C_BaseEntity
  3937. //-----------------------------------------------------------------------------
  3938. C_BaseEntity *C_BaseEntity::Instance( int iEnt )
  3939. {
  3940. return ClientEntityList().GetBaseEntity( iEnt );
  3941. }
  3942. #ifdef WIN32
  3943. #pragma warning( push )
  3944. #include <typeinfo.h>
  3945. #pragma warning( pop )
  3946. #endif
  3947. //-----------------------------------------------------------------------------
  3948. // Purpose:
  3949. // Output : char const
  3950. //-----------------------------------------------------------------------------
  3951. const char *C_BaseEntity::GetClassname( void )
  3952. {
  3953. static char outstr[ 256 ];
  3954. outstr[ 0 ] = 0;
  3955. bool gotname = false;
  3956. #ifndef NO_ENTITY_PREDICTION
  3957. if ( GetPredDescMap() )
  3958. {
  3959. const char *mapname = GetClassMap().Lookup( GetPredDescMap()->dataClassName );
  3960. if ( mapname && mapname[ 0 ] )
  3961. {
  3962. Q_strncpy( outstr, mapname, sizeof( outstr ) );
  3963. gotname = true;
  3964. }
  3965. }
  3966. #endif
  3967. if ( !gotname )
  3968. {
  3969. Q_strncpy( outstr, typeid( *this ).name(), sizeof( outstr ) );
  3970. }
  3971. return outstr;
  3972. }
  3973. const char *C_BaseEntity::GetDebugName( void )
  3974. {
  3975. return GetClassname();
  3976. }
  3977. //-----------------------------------------------------------------------------
  3978. // Purpose: Creates an entity by string name, but does not spawn it
  3979. // Input : *className -
  3980. // Output : C_BaseEntity
  3981. //-----------------------------------------------------------------------------
  3982. C_BaseEntity *CreateEntityByName( const char *className )
  3983. {
  3984. C_BaseEntity *ent = GetClassMap().CreateEntity( className );
  3985. if ( ent )
  3986. {
  3987. return ent;
  3988. }
  3989. Warning( "Can't find factory for entity: %s\n", className );
  3990. return NULL;
  3991. }
  3992. #ifdef _DEBUG
  3993. CON_COMMAND( cl_sizeof, "Determines the size of the specified client class." )
  3994. {
  3995. if ( args.ArgC() != 2 )
  3996. {
  3997. Msg( "cl_sizeof <gameclassname>\n" );
  3998. return;
  3999. }
  4000. int size = GetClassMap().GetClassSize( args[ 1 ] );
  4001. Msg( "%s is %i bytes\n", args[ 1 ], size );
  4002. }
  4003. #endif
  4004. CON_COMMAND_F( dlight_debug, "Creates a dlight in front of the player", FCVAR_CHEAT )
  4005. {
  4006. dlight_t *el = effects->CL_AllocDlight( 1 );
  4007. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  4008. if ( !player )
  4009. return;
  4010. Vector start = player->EyePosition();
  4011. Vector forward;
  4012. player->EyeVectors( &forward );
  4013. Vector end = start + forward * MAX_TRACE_LENGTH;
  4014. trace_t tr;
  4015. UTIL_TraceLine( start, end, MASK_SHOT_HULL & (~CONTENTS_GRATE), player, COLLISION_GROUP_NONE, &tr );
  4016. el->origin = tr.endpos - forward * 12.0f;
  4017. el->radius = 200;
  4018. el->decay = el->radius / 5.0f;
  4019. el->die = gpGlobals->curtime + 5.0f;
  4020. el->color.r = 255;
  4021. el->color.g = 192;
  4022. el->color.b = 64;
  4023. el->color.exponent = 5;
  4024. }
  4025. //-----------------------------------------------------------------------------
  4026. // Purpose:
  4027. // Output : Returns true on success, false on failure.
  4028. //-----------------------------------------------------------------------------
  4029. bool C_BaseEntity::IsClientCreated( void ) const
  4030. {
  4031. #ifndef NO_ENTITY_PREDICTION
  4032. if ( m_pPredictionContext != NULL )
  4033. {
  4034. // For now can't be both
  4035. Assert( !GetPredictable() );
  4036. return true;
  4037. }
  4038. #endif
  4039. return false;
  4040. }
  4041. //-----------------------------------------------------------------------------
  4042. // Purpose:
  4043. // Input : *classname -
  4044. // *module -
  4045. // line -
  4046. // Output : C_BaseEntity
  4047. //-----------------------------------------------------------------------------
  4048. C_BaseEntity *C_BaseEntity::CreatePredictedEntityByName( const char *classname, const char *module, int line, bool persist /*= false */ )
  4049. {
  4050. #if !defined( NO_ENTITY_PREDICTION )
  4051. C_BasePlayer *player = C_BaseEntity::GetPredictionPlayer();
  4052. Assert( player );
  4053. Assert( player->m_pCurrentCommand );
  4054. Assert( prediction->InPrediction() );
  4055. C_BaseEntity *ent = NULL;
  4056. // What's my birthday (should match server)
  4057. int command_number = player->m_pCurrentCommand->command_number;
  4058. // Who's my daddy?
  4059. int player_index = player->entindex() - 1;
  4060. // Create id/context
  4061. CPredictableId testId;
  4062. testId.Init( player_index, command_number, classname, module, line );
  4063. // If repredicting, should be able to find the entity in the previously created list
  4064. if ( !prediction->IsFirstTimePredicted() )
  4065. {
  4066. // Only find previous instance if entity was created with persist set
  4067. if ( persist )
  4068. {
  4069. ent = FindPreviouslyCreatedEntity( testId );
  4070. if ( ent )
  4071. {
  4072. return ent;
  4073. }
  4074. }
  4075. return NULL;
  4076. }
  4077. // Try to create it
  4078. ent = CreateEntityByName( classname );
  4079. if ( !ent )
  4080. {
  4081. return NULL;
  4082. }
  4083. // It's predictable
  4084. ent->SetPredictionEligible( true );
  4085. // Set up "shared" id number
  4086. ent->m_PredictableID.SetRaw( testId.GetRaw() );
  4087. // Get a context (mostly for debugging purposes)
  4088. PredictionContext *context = new PredictionContext;
  4089. context->m_bActive = true;
  4090. context->m_nCreationCommandNumber = command_number;
  4091. context->m_nCreationLineNumber = line;
  4092. context->m_pszCreationModule = module;
  4093. // Attach to entity
  4094. ent->m_pPredictionContext = context;
  4095. // Add to client entity list
  4096. ClientEntityList().AddNonNetworkableEntity( ent );
  4097. // and predictables
  4098. g_Predictables.AddToPredictableList( ent->GetClientHandle() );
  4099. // Duhhhh..., but might as well be safe
  4100. Assert( !ent->GetPredictable() );
  4101. Assert( ent->IsClientCreated() );
  4102. // Add the client entity to the spatial partition. (Collidable)
  4103. ent->CollisionProp()->CreatePartitionHandle();
  4104. // CLIENT ONLY FOR NOW!!!
  4105. ent->index = -1;
  4106. if ( AddDataChangeEvent( ent, DATA_UPDATE_CREATED, &ent->m_DataChangeEventRef ) )
  4107. {
  4108. ent->OnPreDataChanged( DATA_UPDATE_CREATED );
  4109. }
  4110. ent->Interp_UpdateInterpolationAmounts( ent->GetVarMapping() );
  4111. return ent;
  4112. #else
  4113. return NULL;
  4114. #endif
  4115. }
  4116. //-----------------------------------------------------------------------------
  4117. // Purpose: Called each packet that the entity is created on and finally gets called after the next packet
  4118. // that doesn't have a create message for the "parent" entity so that the predicted version
  4119. // can be removed. Return true to delete entity right away.
  4120. //-----------------------------------------------------------------------------
  4121. bool C_BaseEntity::OnPredictedEntityRemove( bool isbeingremoved, C_BaseEntity *predicted )
  4122. {
  4123. #if !defined( NO_ENTITY_PREDICTION )
  4124. // Nothing right now, but in theory you could look at the error in origins and set
  4125. // up something to smooth out the error
  4126. PredictionContext *ctx = predicted->m_pPredictionContext;
  4127. Assert( ctx );
  4128. if ( ctx )
  4129. {
  4130. // Create backlink to actual entity
  4131. ctx->m_hServerEntity = this;
  4132. /*
  4133. Msg( "OnPredictedEntity%s: %s created %s(%i) instance(%i)\n",
  4134. isbeingremoved ? "Remove" : "Acknowledge",
  4135. predicted->GetClassname(),
  4136. ctx->m_pszCreationModule,
  4137. ctx->m_nCreationLineNumber,
  4138. predicted->m_PredictableID.GetInstanceNumber() );
  4139. */
  4140. }
  4141. // If it comes through with an ID, it should be eligible
  4142. SetPredictionEligible( true );
  4143. // Start predicting simulation forward from here
  4144. CheckInitPredictable( "OnPredictedEntityRemove" );
  4145. // Always mark it dormant since we are the "real" entity now
  4146. predicted->SetDormantPredictable( true );
  4147. InvalidatePhysicsRecursive( POSITION_CHANGED | ANGLES_CHANGED | VELOCITY_CHANGED );
  4148. // By default, signal that it should be deleted right away
  4149. // If a derived class implements this method, it might chain to here but return
  4150. // false if it wants to keep the dormant predictable around until the chain of
  4151. // DATA_UPDATE_CREATED messages passes
  4152. #endif
  4153. return true;
  4154. }
  4155. //-----------------------------------------------------------------------------
  4156. // Purpose:
  4157. // Input : *pOwner -
  4158. //-----------------------------------------------------------------------------
  4159. void C_BaseEntity::SetOwnerEntity( C_BaseEntity *pOwner )
  4160. {
  4161. m_hOwnerEntity = pOwner;
  4162. }
  4163. //-----------------------------------------------------------------------------
  4164. // Purpose: Put the entity in the specified team
  4165. //-----------------------------------------------------------------------------
  4166. void C_BaseEntity::ChangeTeam( int iTeamNum )
  4167. {
  4168. m_iTeamNum = iTeamNum;
  4169. }
  4170. //-----------------------------------------------------------------------------
  4171. // Purpose:
  4172. // Input : name -
  4173. //-----------------------------------------------------------------------------
  4174. void C_BaseEntity::SetModelName( string_t name )
  4175. {
  4176. m_ModelName = name;
  4177. }
  4178. //-----------------------------------------------------------------------------
  4179. // Purpose:
  4180. // Output : string_t
  4181. //-----------------------------------------------------------------------------
  4182. string_t C_BaseEntity::GetModelName( void ) const
  4183. {
  4184. return m_ModelName;
  4185. }
  4186. //-----------------------------------------------------------------------------
  4187. // Purpose: Nothing yet, could eventually supercede Term()
  4188. //-----------------------------------------------------------------------------
  4189. void C_BaseEntity::UpdateOnRemove( void )
  4190. {
  4191. VPhysicsDestroyObject();
  4192. Assert( !GetMoveParent() );
  4193. UnlinkFromHierarchy();
  4194. SetGroundEntity( NULL );
  4195. }
  4196. //-----------------------------------------------------------------------------
  4197. // Purpose:
  4198. // Input : canpredict -
  4199. //-----------------------------------------------------------------------------
  4200. void C_BaseEntity::SetPredictionEligible( bool canpredict )
  4201. {
  4202. #if !defined( NO_ENTITY_PREDICTION )
  4203. m_bPredictionEligible = canpredict;
  4204. #endif
  4205. }
  4206. //-----------------------------------------------------------------------------
  4207. // Purpose: Returns a value that scales all damage done by this entity.
  4208. //-----------------------------------------------------------------------------
  4209. float C_BaseEntity::GetAttackDamageScale( void )
  4210. {
  4211. float flScale = 1;
  4212. // Not hooked up to prediction yet
  4213. #if 0
  4214. FOR_EACH_LL( m_DamageModifiers, i )
  4215. {
  4216. if ( !m_DamageModifiers[i]->IsDamageDoneToMe() )
  4217. {
  4218. flScale *= m_DamageModifiers[i]->GetModifier();
  4219. }
  4220. }
  4221. #endif
  4222. return flScale;
  4223. }
  4224. #if !defined( NO_ENTITY_PREDICTION )
  4225. //-----------------------------------------------------------------------------
  4226. // Purpose:
  4227. // Output : Returns true on success, false on failure.
  4228. //-----------------------------------------------------------------------------
  4229. bool C_BaseEntity::IsDormantPredictable( void ) const
  4230. {
  4231. return m_bDormantPredictable;
  4232. }
  4233. #endif
  4234. //-----------------------------------------------------------------------------
  4235. // Purpose:
  4236. // Input : dormant -
  4237. //-----------------------------------------------------------------------------
  4238. void C_BaseEntity::SetDormantPredictable( bool dormant )
  4239. {
  4240. #if !defined( NO_ENTITY_PREDICTION )
  4241. Assert( IsClientCreated() );
  4242. m_bDormantPredictable = true;
  4243. m_nIncomingPacketEntityBecameDormant = prediction->GetIncomingPacketNumber();
  4244. // Do we need to do the following kinds of things?
  4245. #if 0
  4246. // Remove from collisions
  4247. SetSolid( SOLID_NOT );
  4248. // Don't render
  4249. AddEffects( EF_NODRAW );
  4250. #endif
  4251. #endif
  4252. }
  4253. //-----------------------------------------------------------------------------
  4254. // Purpose: Used to determine when a dorman client predictable can be safely deleted
  4255. // Note that it can be deleted earlier than this by OnPredictedEntityRemove returning true
  4256. // Output : Returns true on success, false on failure.
  4257. //-----------------------------------------------------------------------------
  4258. bool C_BaseEntity::BecameDormantThisPacket( void ) const
  4259. {
  4260. #if !defined( NO_ENTITY_PREDICTION )
  4261. Assert( IsDormantPredictable() );
  4262. if ( m_nIncomingPacketEntityBecameDormant != prediction->GetIncomingPacketNumber() )
  4263. return false;
  4264. return true;
  4265. #else
  4266. return false;
  4267. #endif
  4268. }
  4269. //-----------------------------------------------------------------------------
  4270. // Purpose:
  4271. // Output : Returns true on success, false on failure.
  4272. //-----------------------------------------------------------------------------
  4273. bool C_BaseEntity::IsIntermediateDataAllocated( void ) const
  4274. {
  4275. #if !defined( NO_ENTITY_PREDICTION )
  4276. return m_pOriginalData != NULL ? true : false;
  4277. #else
  4278. return false;
  4279. #endif
  4280. }
  4281. //-----------------------------------------------------------------------------
  4282. // Purpose:
  4283. //-----------------------------------------------------------------------------
  4284. void C_BaseEntity::AllocateIntermediateData( void )
  4285. {
  4286. #if !defined( NO_ENTITY_PREDICTION )
  4287. if ( m_pOriginalData )
  4288. return;
  4289. size_t allocsize = GetIntermediateDataSize();
  4290. Assert( allocsize > 0 );
  4291. m_pOriginalData = new unsigned char[ allocsize ];
  4292. Q_memset( m_pOriginalData, 0, allocsize );
  4293. for ( int i = 0; i < MULTIPLAYER_BACKUP; i++ )
  4294. {
  4295. m_pIntermediateData[ i ] = new unsigned char[ allocsize ];
  4296. Q_memset( m_pIntermediateData[ i ], 0, allocsize );
  4297. }
  4298. m_nIntermediateDataCount = 0;
  4299. #endif
  4300. }
  4301. //-----------------------------------------------------------------------------
  4302. // Purpose:
  4303. //-----------------------------------------------------------------------------
  4304. void C_BaseEntity::DestroyIntermediateData( void )
  4305. {
  4306. #if !defined( NO_ENTITY_PREDICTION )
  4307. if ( !m_pOriginalData )
  4308. return;
  4309. for ( int i = 0; i < MULTIPLAYER_BACKUP; i++ )
  4310. {
  4311. delete[] m_pIntermediateData[ i ];
  4312. m_pIntermediateData[ i ] = NULL;
  4313. }
  4314. delete[] m_pOriginalData;
  4315. m_pOriginalData = NULL;
  4316. m_nIntermediateDataCount = 0;
  4317. #endif
  4318. }
  4319. //-----------------------------------------------------------------------------
  4320. // Purpose:
  4321. // Input : slots_to_remove -
  4322. // number_of_commands_run -
  4323. //-----------------------------------------------------------------------------
  4324. void C_BaseEntity::ShiftIntermediateDataForward( int slots_to_remove, int number_of_commands_run )
  4325. {
  4326. #if !defined( NO_ENTITY_PREDICTION )
  4327. Assert( m_pIntermediateData );
  4328. if ( !m_pIntermediateData )
  4329. return;
  4330. Assert( number_of_commands_run >= slots_to_remove );
  4331. // Just moving pointers, yeah
  4332. CUtlVector< unsigned char * > saved;
  4333. // Remember first slots
  4334. int i = 0;
  4335. for ( ; i < slots_to_remove; i++ )
  4336. {
  4337. saved.AddToTail( m_pIntermediateData[ i ] );
  4338. }
  4339. // Move rest of slots forward up to last slot
  4340. for ( ; i < number_of_commands_run; i++ )
  4341. {
  4342. m_pIntermediateData[ i - slots_to_remove ] = m_pIntermediateData[ i ];
  4343. }
  4344. // Put remembered slots onto end
  4345. for ( i = 0; i < slots_to_remove; i++ )
  4346. {
  4347. int slot = number_of_commands_run - slots_to_remove + i;
  4348. m_pIntermediateData[ slot ] = saved[ i ];
  4349. }
  4350. #endif
  4351. }
  4352. //-----------------------------------------------------------------------------
  4353. // Purpose:
  4354. // Input : framenumber -
  4355. //-----------------------------------------------------------------------------
  4356. void *C_BaseEntity::GetPredictedFrame( int framenumber )
  4357. {
  4358. #if !defined( NO_ENTITY_PREDICTION )
  4359. Assert( framenumber >= 0 );
  4360. if ( !m_pOriginalData )
  4361. {
  4362. Assert( 0 );
  4363. return NULL;
  4364. }
  4365. return (void *)m_pIntermediateData[ framenumber % MULTIPLAYER_BACKUP ];
  4366. #else
  4367. return NULL;
  4368. #endif
  4369. }
  4370. //-----------------------------------------------------------------------------
  4371. // Purpose:
  4372. //-----------------------------------------------------------------------------
  4373. void *C_BaseEntity::GetOriginalNetworkDataObject( void )
  4374. {
  4375. #if !defined( NO_ENTITY_PREDICTION )
  4376. if ( !m_pOriginalData )
  4377. {
  4378. Assert( 0 );
  4379. return NULL;
  4380. }
  4381. return (void *)m_pOriginalData;
  4382. #else
  4383. return NULL;
  4384. #endif
  4385. }
  4386. //-----------------------------------------------------------------------------
  4387. // Purpose:
  4388. //-----------------------------------------------------------------------------
  4389. void C_BaseEntity::ComputePackedOffsets( void )
  4390. {
  4391. #if !defined( NO_ENTITY_PREDICTION )
  4392. datamap_t *map = GetPredDescMap();
  4393. if ( !map )
  4394. return;
  4395. if ( map->packed_offsets_computed )
  4396. return;
  4397. ComputePackedSize_R( map );
  4398. Assert( map->packed_offsets_computed );
  4399. #endif
  4400. }
  4401. //-----------------------------------------------------------------------------
  4402. // Purpose:
  4403. // Output : int
  4404. //-----------------------------------------------------------------------------
  4405. int C_BaseEntity::GetIntermediateDataSize( void )
  4406. {
  4407. #if !defined( NO_ENTITY_PREDICTION )
  4408. ComputePackedOffsets();
  4409. const datamap_t *map = GetPredDescMap();
  4410. Assert( map->packed_offsets_computed );
  4411. int size = map->packed_size;
  4412. Assert( size > 0 );
  4413. // At least 4 bytes to avoid some really bad stuff
  4414. return MAX( size, 4 );
  4415. #else
  4416. return 0;
  4417. #endif
  4418. }
  4419. static int g_FieldSizes[FIELD_TYPECOUNT] =
  4420. {
  4421. 0, // FIELD_VOID
  4422. sizeof(float), // FIELD_FLOAT
  4423. sizeof(int), // FIELD_STRING
  4424. sizeof(Vector), // FIELD_VECTOR
  4425. sizeof(Quaternion), // FIELD_QUATERNION
  4426. sizeof(int), // FIELD_INTEGER
  4427. sizeof(char), // FIELD_BOOLEAN
  4428. sizeof(short), // FIELD_SHORT
  4429. sizeof(char), // FIELD_CHARACTER
  4430. sizeof(color32), // FIELD_COLOR32
  4431. sizeof(int), // FIELD_EMBEDDED (handled specially)
  4432. sizeof(int), // FIELD_CUSTOM (handled specially)
  4433. //---------------------------------
  4434. sizeof(int), // FIELD_CLASSPTR
  4435. sizeof(EHANDLE), // FIELD_EHANDLE
  4436. sizeof(int), // FIELD_EDICT
  4437. sizeof(Vector), // FIELD_POSITION_VECTOR
  4438. sizeof(float), // FIELD_TIME
  4439. sizeof(int), // FIELD_TICK
  4440. sizeof(int), // FIELD_MODELNAME
  4441. sizeof(int), // FIELD_SOUNDNAME
  4442. sizeof(int), // FIELD_INPUT (uses custom type)
  4443. #ifdef GNUC
  4444. // pointer to members under gnuc are 8bytes if you have a virtual func
  4445. sizeof(uint64), // FIELD_FUNCTION
  4446. #else
  4447. sizeof(int *), // FIELD_FUNCTION
  4448. #endif
  4449. sizeof(VMatrix), // FIELD_VMATRIX
  4450. sizeof(VMatrix), // FIELD_VMATRIX_WORLDSPACE
  4451. sizeof(matrix3x4_t),// FIELD_MATRIX3X4_WORLDSPACE // NOTE: Use array(FIELD_FLOAT, 12) for matrix3x4_t NOT in worldspace
  4452. sizeof(interval_t), // FIELD_INTERVAL
  4453. sizeof(int), // FIELD_MODELINDEX
  4454. };
  4455. //-----------------------------------------------------------------------------
  4456. // Purpose:
  4457. // Input : *map -
  4458. // Output : int
  4459. //-----------------------------------------------------------------------------
  4460. int C_BaseEntity::ComputePackedSize_R( datamap_t *map )
  4461. {
  4462. if ( !map )
  4463. {
  4464. Assert( 0 );
  4465. return 0;
  4466. }
  4467. // Already computed
  4468. if ( map->packed_offsets_computed )
  4469. {
  4470. return map->packed_size;
  4471. }
  4472. int current_position = 0;
  4473. // Recurse to base classes first...
  4474. if ( map->baseMap )
  4475. {
  4476. current_position += ComputePackedSize_R( map->baseMap );
  4477. }
  4478. int c = map->dataNumFields;
  4479. int i;
  4480. typedescription_t *field;
  4481. for ( i = 0; i < c; i++ )
  4482. {
  4483. field = &map->dataDesc[ i ];
  4484. // Always descend into embedded types...
  4485. if ( field->fieldType != FIELD_EMBEDDED )
  4486. {
  4487. // Skip all private fields
  4488. if ( field->flags & FTYPEDESC_PRIVATE )
  4489. continue;
  4490. }
  4491. switch ( field->fieldType )
  4492. {
  4493. default:
  4494. case FIELD_MODELINDEX:
  4495. case FIELD_MODELNAME:
  4496. case FIELD_SOUNDNAME:
  4497. case FIELD_TIME:
  4498. case FIELD_TICK:
  4499. case FIELD_CUSTOM:
  4500. case FIELD_CLASSPTR:
  4501. case FIELD_EDICT:
  4502. case FIELD_POSITION_VECTOR:
  4503. case FIELD_FUNCTION:
  4504. Assert( 0 );
  4505. break;
  4506. case FIELD_EMBEDDED:
  4507. {
  4508. Assert( field->td != NULL );
  4509. int embeddedsize = ComputePackedSize_R( field->td );
  4510. field->fieldOffset[ TD_OFFSET_PACKED ] = current_position;
  4511. current_position += embeddedsize;
  4512. }
  4513. break;
  4514. case FIELD_FLOAT:
  4515. case FIELD_VECTOR:
  4516. case FIELD_QUATERNION:
  4517. case FIELD_INTEGER:
  4518. case FIELD_EHANDLE:
  4519. {
  4520. // These should be dword aligned
  4521. current_position = (current_position + 3) & ~3;
  4522. field->fieldOffset[ TD_OFFSET_PACKED ] = current_position;
  4523. Assert( field->fieldSize >= 1 );
  4524. current_position += g_FieldSizes[ field->fieldType ] * field->fieldSize;
  4525. }
  4526. break;
  4527. case FIELD_SHORT:
  4528. {
  4529. // This should be word aligned
  4530. current_position = (current_position + 1) & ~1;
  4531. field->fieldOffset[ TD_OFFSET_PACKED ] = current_position;
  4532. Assert( field->fieldSize >= 1 );
  4533. current_position += g_FieldSizes[ field->fieldType ] * field->fieldSize;
  4534. }
  4535. break;
  4536. case FIELD_STRING:
  4537. case FIELD_COLOR32:
  4538. case FIELD_BOOLEAN:
  4539. case FIELD_CHARACTER:
  4540. {
  4541. field->fieldOffset[ TD_OFFSET_PACKED ] = current_position;
  4542. Assert( field->fieldSize >= 1 );
  4543. current_position += g_FieldSizes[ field->fieldType ] * field->fieldSize;
  4544. }
  4545. break;
  4546. case FIELD_VOID:
  4547. {
  4548. // Special case, just skip it
  4549. }
  4550. break;
  4551. }
  4552. }
  4553. map->packed_size = current_position;
  4554. map->packed_offsets_computed = true;
  4555. return current_position;
  4556. }
  4557. // Convenient way to delay removing oneself
  4558. void C_BaseEntity::SUB_Remove( void )
  4559. {
  4560. if (m_iHealth > 0)
  4561. {
  4562. // this situation can screw up NPCs who can't tell their entity pointers are invalid.
  4563. m_iHealth = 0;
  4564. DevWarning( 2, "SUB_Remove called on entity with health > 0\n");
  4565. }
  4566. Remove( );
  4567. }
  4568. CBaseEntity *FindEntityInFrontOfLocalPlayer()
  4569. {
  4570. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  4571. if ( pPlayer )
  4572. {
  4573. // Get the entity under my crosshair
  4574. trace_t tr;
  4575. Vector forward;
  4576. pPlayer->EyeVectors( &forward );
  4577. UTIL_TraceLine( pPlayer->EyePosition(), pPlayer->EyePosition() + forward * MAX_COORD_RANGE, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
  4578. if ( tr.fraction != 1.0 && tr.DidHitNonWorldEntity() )
  4579. {
  4580. return tr.m_pEnt;
  4581. }
  4582. }
  4583. return NULL;
  4584. }
  4585. //-----------------------------------------------------------------------------
  4586. // Purpose: Debug command to wipe the decals off an entity
  4587. //-----------------------------------------------------------------------------
  4588. static void RemoveDecals_f( void )
  4589. {
  4590. CBaseEntity *pHit = FindEntityInFrontOfLocalPlayer();
  4591. if ( pHit )
  4592. {
  4593. pHit->RemoveAllDecals();
  4594. }
  4595. }
  4596. static ConCommand cl_removedecals( "cl_removedecals", RemoveDecals_f, "Remove the decals from the entity under the crosshair.", FCVAR_CHEAT );
  4597. //-----------------------------------------------------------------------------
  4598. // Purpose:
  4599. //-----------------------------------------------------------------------------
  4600. void C_BaseEntity::ToggleBBoxVisualization( int fVisFlags )
  4601. {
  4602. if ( m_fBBoxVisFlags & fVisFlags )
  4603. {
  4604. m_fBBoxVisFlags &= ~fVisFlags;
  4605. }
  4606. else
  4607. {
  4608. m_fBBoxVisFlags |= fVisFlags;
  4609. }
  4610. }
  4611. //-----------------------------------------------------------------------------
  4612. // Purpose:
  4613. //-----------------------------------------------------------------------------
  4614. static void ToggleBBoxVisualization( int fVisFlags, const CCommand &args )
  4615. {
  4616. CBaseEntity *pHit;
  4617. int iEntity = -1;
  4618. if ( args.ArgC() >= 2 )
  4619. {
  4620. iEntity = atoi( args[ 1 ] );
  4621. }
  4622. if ( iEntity == -1 )
  4623. {
  4624. pHit = FindEntityInFrontOfLocalPlayer();
  4625. }
  4626. else
  4627. {
  4628. pHit = cl_entitylist->GetBaseEntity( iEntity );
  4629. }
  4630. if ( pHit )
  4631. {
  4632. pHit->ToggleBBoxVisualization( fVisFlags );
  4633. }
  4634. }
  4635. //-----------------------------------------------------------------------------
  4636. // Purpose: Command to toggle visualizations of bboxes on the client
  4637. //-----------------------------------------------------------------------------
  4638. CON_COMMAND_F( cl_ent_bbox, "Displays the client's bounding box for the entity under the crosshair.", FCVAR_CHEAT )
  4639. {
  4640. ToggleBBoxVisualization( CBaseEntity::VISUALIZE_COLLISION_BOUNDS, args );
  4641. }
  4642. //-----------------------------------------------------------------------------
  4643. // Purpose: Command to toggle visualizations of bboxes on the client
  4644. //-----------------------------------------------------------------------------
  4645. CON_COMMAND_F( cl_ent_absbox, "Displays the client's absbox for the entity under the crosshair.", FCVAR_CHEAT )
  4646. {
  4647. ToggleBBoxVisualization( CBaseEntity::VISUALIZE_SURROUNDING_BOUNDS, args );
  4648. }
  4649. //-----------------------------------------------------------------------------
  4650. // Purpose: Command to toggle visualizations of bboxes on the client
  4651. //-----------------------------------------------------------------------------
  4652. CON_COMMAND_F( cl_ent_rbox, "Displays the client's render box for the entity under the crosshair.", FCVAR_CHEAT )
  4653. {
  4654. ToggleBBoxVisualization( CBaseEntity::VISUALIZE_RENDER_BOUNDS, args );
  4655. }
  4656. //-----------------------------------------------------------------------------
  4657. // Purpose:
  4658. //-----------------------------------------------------------------------------
  4659. void C_BaseEntity::DrawBBoxVisualizations( void )
  4660. {
  4661. if ( m_fBBoxVisFlags & VISUALIZE_COLLISION_BOUNDS )
  4662. {
  4663. debugoverlay->AddBoxOverlay( CollisionProp()->GetCollisionOrigin(), CollisionProp()->OBBMins(),
  4664. CollisionProp()->OBBMaxs(), CollisionProp()->GetCollisionAngles(), 190, 190, 0, 0, 0.01 );
  4665. }
  4666. if ( m_fBBoxVisFlags & VISUALIZE_SURROUNDING_BOUNDS )
  4667. {
  4668. Vector vecSurroundMins, vecSurroundMaxs;
  4669. CollisionProp()->WorldSpaceSurroundingBounds( &vecSurroundMins, &vecSurroundMaxs );
  4670. debugoverlay->AddBoxOverlay( vec3_origin, vecSurroundMins,
  4671. vecSurroundMaxs, vec3_angle, 0, 255, 255, 0, 0.01 );
  4672. }
  4673. if ( m_fBBoxVisFlags & VISUALIZE_RENDER_BOUNDS || r_drawrenderboxes.GetInt() )
  4674. {
  4675. Vector vecRenderMins, vecRenderMaxs;
  4676. GetRenderBounds( vecRenderMins, vecRenderMaxs );
  4677. debugoverlay->AddBoxOverlay( GetRenderOrigin(), vecRenderMins, vecRenderMaxs,
  4678. GetRenderAngles(), 255, 0, 255, 0, 0.01 );
  4679. }
  4680. }
  4681. //-----------------------------------------------------------------------------
  4682. // Sets the render mode
  4683. //-----------------------------------------------------------------------------
  4684. void C_BaseEntity::SetRenderMode( RenderMode_t nRenderMode, bool bForceUpdate )
  4685. {
  4686. m_nRenderMode = nRenderMode;
  4687. }
  4688. //-----------------------------------------------------------------------------
  4689. // Purpose:
  4690. // Output : RenderGroup_t
  4691. //-----------------------------------------------------------------------------
  4692. RenderGroup_t C_BaseEntity::GetRenderGroup()
  4693. {
  4694. // Don't sort things that don't need rendering
  4695. if ( m_nRenderMode == kRenderNone )
  4696. return RENDER_GROUP_OPAQUE_ENTITY;
  4697. // When an entity has a material proxy, we have to recompute
  4698. // translucency here because the proxy may have changed it.
  4699. if (modelinfo->ModelHasMaterialProxy( GetModel() ))
  4700. {
  4701. modelinfo->RecomputeTranslucency( const_cast<model_t*>(GetModel()), GetSkin(), GetBody(), GetClientRenderable() );
  4702. }
  4703. // NOTE: Bypassing the GetFXBlend protection logic because we want this to
  4704. // be able to be called from AddToLeafSystem.
  4705. int nTempComputeFrame = m_nFXComputeFrame;
  4706. m_nFXComputeFrame = gpGlobals->framecount;
  4707. int nFXBlend = GetFxBlend();
  4708. m_nFXComputeFrame = nTempComputeFrame;
  4709. // Don't need to sort invisible stuff
  4710. if ( nFXBlend == 0 )
  4711. return RENDER_GROUP_OPAQUE_ENTITY;
  4712. // Figure out its RenderGroup.
  4713. int modelType = modelinfo->GetModelType( model );
  4714. RenderGroup_t renderGroup = (modelType == mod_brush) ? RENDER_GROUP_OPAQUE_BRUSH : RENDER_GROUP_OPAQUE_ENTITY;
  4715. if ( ( nFXBlend != 255 ) || IsTransparent() )
  4716. {
  4717. if ( m_nRenderMode != kRenderEnvironmental )
  4718. {
  4719. renderGroup = RENDER_GROUP_TRANSLUCENT_ENTITY;
  4720. }
  4721. else
  4722. {
  4723. renderGroup = RENDER_GROUP_OTHER;
  4724. }
  4725. }
  4726. if ( ( renderGroup == RENDER_GROUP_TRANSLUCENT_ENTITY ) &&
  4727. ( modelinfo->IsTranslucentTwoPass( model ) ) )
  4728. {
  4729. renderGroup = RENDER_GROUP_TWOPASS;
  4730. }
  4731. return renderGroup;
  4732. }
  4733. //-----------------------------------------------------------------------------
  4734. // Purpose: Copy from this entity into one of the save slots (original or intermediate)
  4735. // Input : slot -
  4736. // type -
  4737. // false -
  4738. // false -
  4739. // true -
  4740. // false -
  4741. // NULL -
  4742. // Output : int
  4743. //-----------------------------------------------------------------------------
  4744. int C_BaseEntity::SaveData( const char *context, int slot, int type )
  4745. {
  4746. #if !defined( NO_ENTITY_PREDICTION )
  4747. VPROF( "C_BaseEntity::SaveData" );
  4748. void *dest = ( slot == SLOT_ORIGINALDATA ) ? GetOriginalNetworkDataObject() : GetPredictedFrame( slot );
  4749. Assert( dest );
  4750. char sz[ 64 ];
  4751. sz[0] = 0;
  4752. // don't build debug strings per entity per frame, unless we are watching the entity
  4753. static ConVarRef pwatchent( "pwatchent" );
  4754. if ( pwatchent.GetInt() == entindex() )
  4755. {
  4756. if ( slot == SLOT_ORIGINALDATA )
  4757. {
  4758. Q_snprintf( sz, sizeof( sz ), "%s SaveData(original)", context );
  4759. }
  4760. else
  4761. {
  4762. Q_snprintf( sz, sizeof( sz ), "%s SaveData(slot %02i)", context, slot );
  4763. }
  4764. }
  4765. if ( slot != SLOT_ORIGINALDATA )
  4766. {
  4767. // Remember high water mark so that we can detect below if we are reading from a slot not yet predicted into...
  4768. m_nIntermediateDataCount = slot;
  4769. }
  4770. CPredictionCopy copyHelper( type, dest, PC_DATA_PACKED, this, PC_DATA_NORMAL );
  4771. int error_count = copyHelper.TransferData( sz, entindex(), GetPredDescMap() );
  4772. return error_count;
  4773. #else
  4774. return 0;
  4775. #endif
  4776. }
  4777. //-----------------------------------------------------------------------------
  4778. // Purpose: Restore data from specified slot into current entity
  4779. // Input : slot -
  4780. // type -
  4781. // false -
  4782. // false -
  4783. // true -
  4784. // false -
  4785. // NULL -
  4786. // Output : int
  4787. //-----------------------------------------------------------------------------
  4788. int C_BaseEntity::RestoreData( const char *context, int slot, int type )
  4789. {
  4790. #if !defined( NO_ENTITY_PREDICTION )
  4791. VPROF( "C_BaseEntity::RestoreData" );
  4792. const void *src = ( slot == SLOT_ORIGINALDATA ) ? GetOriginalNetworkDataObject() : GetPredictedFrame( slot );
  4793. Assert( src );
  4794. // This assert will fire if the server ack'd a CUserCmd which we hadn't predicted yet...
  4795. // In that case, we'd be comparing "old" data from this "unused" slot with the networked data and reporting all kinds of prediction errors possibly.
  4796. Assert( slot == SLOT_ORIGINALDATA || slot <= m_nIntermediateDataCount );
  4797. char sz[ 64 ];
  4798. sz[0] = 0;
  4799. // don't build debug strings per entity per frame, unless we are watching the entity
  4800. static ConVarRef pwatchent( "pwatchent" );
  4801. if ( pwatchent.GetInt() == entindex() )
  4802. {
  4803. if ( slot == SLOT_ORIGINALDATA )
  4804. {
  4805. Q_snprintf( sz, sizeof( sz ), "%s RestoreData(original)", context );
  4806. }
  4807. else
  4808. {
  4809. Q_snprintf( sz, sizeof( sz ), "%s RestoreData(slot %02i)", context, slot );
  4810. }
  4811. }
  4812. // some flags shouldn't be predicted - as we find them, add them to the savedEFlagsMask
  4813. const int savedEFlagsMask = EFL_DIRTY_SHADOWUPDATE;
  4814. int savedEFlags = GetEFlags() & savedEFlagsMask;
  4815. // model index needs to be set manually for dynamic model refcounting purposes
  4816. int oldModelIndex = m_nModelIndex;
  4817. CPredictionCopy copyHelper( type, this, PC_DATA_NORMAL, src, PC_DATA_PACKED );
  4818. int error_count = copyHelper.TransferData( sz, entindex(), GetPredDescMap() );
  4819. // set non-predicting flags back to their prior state
  4820. RemoveEFlags( savedEFlagsMask );
  4821. AddEFlags( savedEFlags );
  4822. // restore original model index and change via SetModelIndex
  4823. int newModelIndex = m_nModelIndex;
  4824. m_nModelIndex = oldModelIndex;
  4825. int overrideModelIndex = CalcOverrideModelIndex();
  4826. if( overrideModelIndex != -1 )
  4827. newModelIndex = overrideModelIndex;
  4828. if ( oldModelIndex != newModelIndex )
  4829. {
  4830. MDLCACHE_CRITICAL_SECTION(); // ???
  4831. SetModelIndex( newModelIndex );
  4832. }
  4833. OnPostRestoreData();
  4834. return error_count;
  4835. #else
  4836. return 0;
  4837. #endif
  4838. }
  4839. void C_BaseEntity::OnPostRestoreData()
  4840. {
  4841. // HACK Force recomputation of origin
  4842. InvalidatePhysicsRecursive( POSITION_CHANGED | ANGLES_CHANGED | VELOCITY_CHANGED );
  4843. if ( GetMoveParent() )
  4844. {
  4845. AddToAimEntsList();
  4846. }
  4847. // If our model index has changed, then make sure it's reflected in our model pointer.
  4848. // (Mostly superseded by new modelindex delta check in RestoreData, but I'm leaving it
  4849. // because it might be band-aiding any other missed calls to SetModelByIndex --henryg)
  4850. if ( GetModel() != modelinfo->GetModel( GetModelIndex() ) )
  4851. {
  4852. MDLCACHE_CRITICAL_SECTION();
  4853. SetModelByIndex( GetModelIndex() );
  4854. }
  4855. }
  4856. //-----------------------------------------------------------------------------
  4857. // Purpose: Determine approximate velocity based on updates from server
  4858. // Input : vel -
  4859. //-----------------------------------------------------------------------------
  4860. void C_BaseEntity::EstimateAbsVelocity( Vector& vel )
  4861. {
  4862. if ( this == C_BasePlayer::GetLocalPlayer() )
  4863. {
  4864. // This is interpolated and networked
  4865. vel = GetAbsVelocity();
  4866. return;
  4867. }
  4868. CInterpolationContext context;
  4869. context.EnableExtrapolation( true );
  4870. m_iv_vecOrigin.GetDerivative_SmoothVelocity( &vel, gpGlobals->curtime );
  4871. }
  4872. void C_BaseEntity::Interp_Reset( VarMapping_t *map )
  4873. {
  4874. PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, "reset" );
  4875. int c = map->m_Entries.Count();
  4876. for ( int i = 0; i < c; i++ )
  4877. {
  4878. VarMapEntry_t *e = &map->m_Entries[ i ];
  4879. IInterpolatedVar *watcher = e->watcher;
  4880. watcher->Reset();
  4881. }
  4882. }
  4883. void C_BaseEntity::ResetLatched()
  4884. {
  4885. if ( IsClientCreated() )
  4886. return;
  4887. Interp_Reset( GetVarMapping() );
  4888. }
  4889. //-----------------------------------------------------------------------------
  4890. // Purpose: Fixme, this needs a better solution
  4891. // Input : flags -
  4892. // Output : float
  4893. //-----------------------------------------------------------------------------
  4894. static float AdjustInterpolationAmount( C_BaseEntity *pEntity, float baseInterpolation )
  4895. {
  4896. if ( cl_interp_npcs.GetFloat() > 0 )
  4897. {
  4898. const float minNPCInterpolationTime = cl_interp_npcs.GetFloat();
  4899. const float minNPCInterpolation = TICK_INTERVAL * ( TIME_TO_TICKS( minNPCInterpolationTime ) + 1 );
  4900. if ( minNPCInterpolation > baseInterpolation )
  4901. {
  4902. while ( pEntity )
  4903. {
  4904. if ( pEntity->IsNPC() )
  4905. return minNPCInterpolation;
  4906. pEntity = pEntity->GetMoveParent();
  4907. }
  4908. }
  4909. }
  4910. return baseInterpolation;
  4911. }
  4912. //-------------------------------------
  4913. float C_BaseEntity::GetInterpolationAmount( int flags )
  4914. {
  4915. // If single player server is "skipping ticks" everything needs to interpolate for a bit longer
  4916. int serverTickMultiple = 1;
  4917. if ( IsSimulatingOnAlternateTicks() )
  4918. {
  4919. serverTickMultiple = 2;
  4920. }
  4921. if ( GetPredictable() || IsClientCreated() )
  4922. {
  4923. return TICK_INTERVAL * serverTickMultiple;
  4924. }
  4925. // Always fully interpolate during multi-player or during demo playback, if the recorded
  4926. // demo was recorded locally.
  4927. const bool bPlayingDemo = engine->IsPlayingDemo();
  4928. const bool bPlayingMultiplayer = !bPlayingDemo && ( gpGlobals->maxClients > 1 );
  4929. const bool bPlayingNonLocallyRecordedDemo = bPlayingDemo && !engine->IsPlayingDemoALocallyRecordedDemo();
  4930. if ( bPlayingMultiplayer || bPlayingNonLocallyRecordedDemo )
  4931. {
  4932. return AdjustInterpolationAmount( this, TICKS_TO_TIME( TIME_TO_TICKS( GetClientInterpAmount() ) + serverTickMultiple ) );
  4933. }
  4934. int expandedServerTickMultiple = serverTickMultiple;
  4935. if ( IsEngineThreaded() )
  4936. {
  4937. expandedServerTickMultiple += g_nThreadModeTicks;
  4938. }
  4939. if ( IsAnimatedEveryTick() && IsSimulatedEveryTick() )
  4940. {
  4941. return TICK_INTERVAL * expandedServerTickMultiple;
  4942. }
  4943. if ( ( flags & LATCH_ANIMATION_VAR ) && IsAnimatedEveryTick() )
  4944. {
  4945. return TICK_INTERVAL * expandedServerTickMultiple;
  4946. }
  4947. if ( ( flags & LATCH_SIMULATION_VAR ) && IsSimulatedEveryTick() )
  4948. {
  4949. return TICK_INTERVAL * expandedServerTickMultiple;
  4950. }
  4951. return AdjustInterpolationAmount( this, TICKS_TO_TIME( TIME_TO_TICKS( GetClientInterpAmount() ) + serverTickMultiple ) );
  4952. }
  4953. float C_BaseEntity::GetLastChangeTime( int flags )
  4954. {
  4955. if ( GetPredictable() || IsClientCreated() )
  4956. {
  4957. return gpGlobals->curtime;
  4958. }
  4959. // make sure not both flags are set, we can't resolve that
  4960. Assert( !( (flags & LATCH_ANIMATION_VAR) && (flags & LATCH_SIMULATION_VAR) ) );
  4961. if ( flags & LATCH_ANIMATION_VAR )
  4962. {
  4963. return GetAnimTime();
  4964. }
  4965. if ( flags & LATCH_SIMULATION_VAR )
  4966. {
  4967. float st = GetSimulationTime();
  4968. if ( st == 0.0f )
  4969. {
  4970. return gpGlobals->curtime;
  4971. }
  4972. return st;
  4973. }
  4974. Assert( 0 );
  4975. return gpGlobals->curtime;
  4976. }
  4977. const Vector& C_BaseEntity::GetPrevLocalOrigin() const
  4978. {
  4979. return m_iv_vecOrigin.GetPrev();
  4980. }
  4981. const QAngle& C_BaseEntity::GetPrevLocalAngles() const
  4982. {
  4983. return m_iv_angRotation.GetPrev();
  4984. }
  4985. //-----------------------------------------------------------------------------
  4986. // Simply here for game shared
  4987. //-----------------------------------------------------------------------------
  4988. bool C_BaseEntity::IsFloating()
  4989. {
  4990. // NOTE: This is only here because it's called by game shared.
  4991. // The server uses it to lower falling impact damage
  4992. return false;
  4993. }
  4994. BEGIN_DATADESC_NO_BASE( C_BaseEntity )
  4995. DEFINE_FIELD( m_ModelName, FIELD_STRING ),
  4996. DEFINE_FIELD( m_vecAbsOrigin, FIELD_POSITION_VECTOR ),
  4997. DEFINE_FIELD( m_angAbsRotation, FIELD_VECTOR ),
  4998. DEFINE_ARRAY( m_rgflCoordinateFrame, FIELD_FLOAT, 12 ), // NOTE: MUST BE IN LOCAL SPACE, NOT POSITION_VECTOR!!! (see CBaseEntity::Restore)
  4999. DEFINE_FIELD( m_fFlags, FIELD_INTEGER ),
  5000. END_DATADESC()
  5001. //-----------------------------------------------------------------------------
  5002. // Purpose:
  5003. // Output : Returns true on success, false on failure.
  5004. //-----------------------------------------------------------------------------
  5005. bool C_BaseEntity::ShouldSavePhysics()
  5006. {
  5007. return false;
  5008. }
  5009. //-----------------------------------------------------------------------------
  5010. // handler to do stuff before you are saved
  5011. //-----------------------------------------------------------------------------
  5012. void C_BaseEntity::OnSave()
  5013. {
  5014. // Here, we must force recomputation of all abs data so it gets saved correctly
  5015. // We can't leave the dirty bits set because the loader can't cope with it.
  5016. CalcAbsolutePosition();
  5017. CalcAbsoluteVelocity();
  5018. }
  5019. //-----------------------------------------------------------------------------
  5020. // handler to do stuff after you are restored
  5021. //-----------------------------------------------------------------------------
  5022. void C_BaseEntity::OnRestore()
  5023. {
  5024. InvalidatePhysicsRecursive( POSITION_CHANGED | ANGLES_CHANGED | VELOCITY_CHANGED );
  5025. UpdatePartitionListEntry();
  5026. CollisionProp()->UpdatePartition();
  5027. UpdateVisibility();
  5028. }
  5029. //-----------------------------------------------------------------------------
  5030. // Purpose: Saves the current object out to disk, by iterating through the objects
  5031. // data description hierarchy
  5032. // Input : &save - save buffer which the class data is written to
  5033. // Output : int - 0 if the save failed, 1 on success
  5034. //-----------------------------------------------------------------------------
  5035. int C_BaseEntity::Save( ISave &save )
  5036. {
  5037. // loop through the data description list, saving each data desc block
  5038. int status = SaveDataDescBlock( save, GetDataDescMap() );
  5039. return status;
  5040. }
  5041. //-----------------------------------------------------------------------------
  5042. // Purpose: Recursively saves all the classes in an object, in reverse order (top down)
  5043. // Output : int 0 on failure, 1 on success
  5044. //-----------------------------------------------------------------------------
  5045. int C_BaseEntity::SaveDataDescBlock( ISave &save, datamap_t *dmap )
  5046. {
  5047. int nResult = save.WriteAll( this, dmap );
  5048. return nResult;
  5049. }
  5050. void C_BaseEntity::SetClassname( const char *className )
  5051. {
  5052. m_iClassname = MAKE_STRING( className );
  5053. }
  5054. //-----------------------------------------------------------------------------
  5055. // Purpose: Restores the current object from disk, by iterating through the objects
  5056. // data description hierarchy
  5057. // Input : &restore - restore buffer which the class data is read from
  5058. // Output : int - 0 if the restore failed, 1 on success
  5059. //-----------------------------------------------------------------------------
  5060. int C_BaseEntity::Restore( IRestore &restore )
  5061. {
  5062. // loops through the data description list, restoring each data desc block in order
  5063. int status = RestoreDataDescBlock( restore, GetDataDescMap() );
  5064. // NOTE: Do *not* use GetAbsOrigin() here because it will
  5065. // try to recompute m_rgflCoordinateFrame!
  5066. MatrixSetColumn( m_vecAbsOrigin, 3, m_rgflCoordinateFrame );
  5067. // Restablish ground entity
  5068. if ( m_hGroundEntity != NULL )
  5069. {
  5070. m_hGroundEntity->AddEntityToGroundList( this );
  5071. }
  5072. return status;
  5073. }
  5074. //-----------------------------------------------------------------------------
  5075. // Purpose: Recursively restores all the classes in an object, in reverse order (top down)
  5076. // Output : int 0 on failure, 1 on success
  5077. //-----------------------------------------------------------------------------
  5078. int C_BaseEntity::RestoreDataDescBlock( IRestore &restore, datamap_t *dmap )
  5079. {
  5080. return restore.ReadAll( this, dmap );
  5081. }
  5082. //-----------------------------------------------------------------------------
  5083. // capabilities
  5084. //-----------------------------------------------------------------------------
  5085. int C_BaseEntity::ObjectCaps( void )
  5086. {
  5087. return 0;
  5088. }
  5089. //-----------------------------------------------------------------------------
  5090. // Purpose:
  5091. // Output : C_AI_BaseNPC
  5092. //-----------------------------------------------------------------------------
  5093. C_AI_BaseNPC *C_BaseEntity::MyNPCPointer( void )
  5094. {
  5095. if ( IsNPC() )
  5096. {
  5097. return assert_cast<C_AI_BaseNPC *>(this);
  5098. }
  5099. return NULL;
  5100. }
  5101. //-----------------------------------------------------------------------------
  5102. // Purpose: For each client (only can be local client in client .dll ) checks the client has disabled CC and if so, removes them from
  5103. // the recipient list.
  5104. // Input : filter -
  5105. //-----------------------------------------------------------------------------
  5106. void C_BaseEntity::RemoveRecipientsIfNotCloseCaptioning( C_RecipientFilter& filter )
  5107. {
  5108. extern ConVar closecaption;
  5109. if ( !closecaption.GetBool() )
  5110. {
  5111. filter.Reset();
  5112. }
  5113. }
  5114. //-----------------------------------------------------------------------------
  5115. // Purpose:
  5116. // Input : recording -
  5117. // Output : inline void
  5118. //-----------------------------------------------------------------------------
  5119. void C_BaseEntity::EnableInToolView( bool bEnable )
  5120. {
  5121. #ifndef NO_TOOLFRAMEWORK
  5122. m_bEnabledInToolView = bEnable;
  5123. UpdateVisibility();
  5124. #endif
  5125. }
  5126. void C_BaseEntity::SetToolRecording( bool recording )
  5127. {
  5128. #ifndef NO_TOOLFRAMEWORK
  5129. m_bToolRecording = recording;
  5130. if ( m_bToolRecording )
  5131. {
  5132. recordinglist->AddToList( GetClientHandle() );
  5133. }
  5134. else
  5135. {
  5136. recordinglist->RemoveFromList( GetClientHandle() );
  5137. }
  5138. #endif
  5139. }
  5140. bool C_BaseEntity::HasRecordedThisFrame() const
  5141. {
  5142. #ifndef NO_TOOLFRAMEWORK
  5143. Assert( m_nLastRecordedFrame <= gpGlobals->framecount );
  5144. return m_nLastRecordedFrame == gpGlobals->framecount;
  5145. #else
  5146. return false;
  5147. #endif
  5148. }
  5149. void C_BaseEntity::GetToolRecordingState( KeyValues *msg )
  5150. {
  5151. Assert( ToolsEnabled() );
  5152. if ( !ToolsEnabled() )
  5153. return;
  5154. VPROF_BUDGET( "C_BaseEntity::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
  5155. C_BaseEntity *pOwner = m_hOwnerEntity;
  5156. static BaseEntityRecordingState_t state;
  5157. state.m_flTime = gpGlobals->curtime;
  5158. state.m_pModelName = modelinfo->GetModelName( GetModel() );
  5159. state.m_nOwner = pOwner ? pOwner->entindex() : -1;
  5160. state.m_nEffects = m_fEffects;
  5161. state.m_bVisible = ShouldDraw() && !IsDormant();
  5162. state.m_bRecordFinalVisibleSample = false;
  5163. state.m_vecRenderOrigin = GetRenderOrigin();
  5164. state.m_vecRenderAngles = GetRenderAngles();
  5165. // use EF_NOINTERP if the owner or a hierarchical parent has NO_INTERP
  5166. if ( pOwner && pOwner->IsNoInterpolationFrame() )
  5167. {
  5168. state.m_nEffects |= EF_NOINTERP;
  5169. }
  5170. C_BaseEntity *pParent = GetMoveParent();
  5171. while ( pParent )
  5172. {
  5173. if ( pParent->IsNoInterpolationFrame() )
  5174. {
  5175. state.m_nEffects |= EF_NOINTERP;
  5176. break;
  5177. }
  5178. pParent = pParent->GetMoveParent();
  5179. }
  5180. msg->SetPtr( "baseentity", &state );
  5181. }
  5182. void C_BaseEntity::CleanupToolRecordingState( KeyValues *msg )
  5183. {
  5184. }
  5185. void C_BaseEntity::RecordToolMessage()
  5186. {
  5187. Assert( IsToolRecording() );
  5188. if ( !IsToolRecording() )
  5189. return;
  5190. if ( HasRecordedThisFrame() )
  5191. return;
  5192. KeyValues *msg = new KeyValues( "entity_state" );
  5193. // Post a message back to all IToolSystems
  5194. GetToolRecordingState( msg );
  5195. Assert( (int)GetToolHandle() != 0 );
  5196. ToolFramework_PostToolMessage( GetToolHandle(), msg );
  5197. CleanupToolRecordingState( msg );
  5198. msg->deleteThis();
  5199. m_nLastRecordedFrame = gpGlobals->framecount;
  5200. }
  5201. // (static function)
  5202. void C_BaseEntity::ToolRecordEntities()
  5203. {
  5204. VPROF_BUDGET( "C_BaseEntity::ToolRecordEnties", VPROF_BUDGETGROUP_TOOLS );
  5205. if ( !ToolsEnabled() || !clienttools->IsInRecordingMode() )
  5206. return;
  5207. // Let non-dormant client created predictables get added, too
  5208. int c = recordinglist->Count();
  5209. for ( int i = 0 ; i < c ; i++ )
  5210. {
  5211. IClientRenderable *pRenderable = recordinglist->Get( i );
  5212. if ( !pRenderable )
  5213. continue;
  5214. pRenderable->RecordToolMessage();
  5215. }
  5216. }
  5217. void C_BaseEntity::AddToInterpolationList()
  5218. {
  5219. if ( m_InterpolationListEntry == 0xFFFF )
  5220. m_InterpolationListEntry = g_InterpolationList.AddToTail( this );
  5221. }
  5222. void C_BaseEntity::RemoveFromInterpolationList()
  5223. {
  5224. if ( m_InterpolationListEntry != 0xFFFF )
  5225. {
  5226. g_InterpolationList.Remove( m_InterpolationListEntry );
  5227. m_InterpolationListEntry = 0xFFFF;
  5228. }
  5229. }
  5230. void C_BaseEntity::AddToTeleportList()
  5231. {
  5232. if ( m_TeleportListEntry == 0xFFFF )
  5233. m_TeleportListEntry = g_TeleportList.AddToTail( this );
  5234. }
  5235. void C_BaseEntity::RemoveFromTeleportList()
  5236. {
  5237. if ( m_TeleportListEntry != 0xFFFF )
  5238. {
  5239. g_TeleportList.Remove( m_TeleportListEntry );
  5240. m_TeleportListEntry = 0xFFFF;
  5241. }
  5242. }
  5243. #ifdef TF_CLIENT_DLL
  5244. bool C_BaseEntity::ValidateEntityAttachedToPlayer( bool &bShouldRetry )
  5245. {
  5246. bShouldRetry = false;
  5247. C_BaseEntity *pParent = GetRootMoveParent();
  5248. if ( pParent == this )
  5249. return true;
  5250. // Some wearables parent to the view model
  5251. C_BasePlayer *pPlayer = ToBasePlayer( pParent );
  5252. if ( pPlayer && pPlayer->GetViewModel() == this )
  5253. {
  5254. return true;
  5255. }
  5256. // always allow the briefcase model
  5257. const char *pszModel = modelinfo->GetModelName( GetModel() );
  5258. if ( pszModel && pszModel[0] )
  5259. {
  5260. if ( FStrEq( pszModel, "models/flag/briefcase.mdl" ) )
  5261. return true;
  5262. if ( FStrEq( pszModel, "models/props_doomsday/australium_container.mdl" ) )
  5263. return true;
  5264. // Temp for MVM testing
  5265. if ( FStrEq( pszModel, "models/buildables/sapper_placement_sentry1.mdl" ) )
  5266. return true;
  5267. if ( FStrEq( pszModel, "models/props_td/atom_bomb.mdl" ) )
  5268. return true;
  5269. if ( FStrEq( pszModel, "models/props_lakeside_event/bomb_temp_hat.mdl" ) )
  5270. return true;
  5271. }
  5272. // Any entity that's not an item parented to a player is invalid.
  5273. // This prevents them creating some other entity to pretend to be a cosmetic item.
  5274. return !pParent->IsPlayer();
  5275. }
  5276. #endif // TF_CLIENT_DLL
  5277. void C_BaseEntity::AddVar( void *data, IInterpolatedVar *watcher, int type, bool bSetup )
  5278. {
  5279. // Only add it if it hasn't been added yet.
  5280. bool bAddIt = true;
  5281. for ( int i=0; i < m_VarMap.m_Entries.Count(); i++ )
  5282. {
  5283. if ( m_VarMap.m_Entries[i].watcher == watcher )
  5284. {
  5285. if ( (type & EXCLUDE_AUTO_INTERPOLATE) != (watcher->GetType() & EXCLUDE_AUTO_INTERPOLATE) )
  5286. {
  5287. // Its interpolation mode changed, so get rid of it and re-add it.
  5288. RemoveVar( m_VarMap.m_Entries[i].data, true );
  5289. }
  5290. else
  5291. {
  5292. // They're adding something that's already there. No need to re-add it.
  5293. bAddIt = false;
  5294. }
  5295. break;
  5296. }
  5297. }
  5298. if ( bAddIt )
  5299. {
  5300. // watchers must have a debug name set
  5301. Assert( watcher->GetDebugName() != NULL );
  5302. VarMapEntry_t map;
  5303. map.data = data;
  5304. map.watcher = watcher;
  5305. map.type = type;
  5306. map.m_bNeedsToInterpolate = true;
  5307. if ( type & EXCLUDE_AUTO_INTERPOLATE )
  5308. {
  5309. m_VarMap.m_Entries.AddToTail( map );
  5310. }
  5311. else
  5312. {
  5313. m_VarMap.m_Entries.AddToHead( map );
  5314. ++m_VarMap.m_nInterpolatedEntries;
  5315. }
  5316. }
  5317. if ( bSetup )
  5318. {
  5319. watcher->Setup( data, type );
  5320. watcher->SetInterpolationAmount( GetInterpolationAmount( watcher->GetType() ) );
  5321. }
  5322. }
  5323. void C_BaseEntity::RemoveVar( void *data, bool bAssert )
  5324. {
  5325. for ( int i=0; i < m_VarMap.m_Entries.Count(); i++ )
  5326. {
  5327. if ( m_VarMap.m_Entries[i].data == data )
  5328. {
  5329. if ( !( m_VarMap.m_Entries[i].type & EXCLUDE_AUTO_INTERPOLATE ) )
  5330. --m_VarMap.m_nInterpolatedEntries;
  5331. m_VarMap.m_Entries.Remove( i );
  5332. return;
  5333. }
  5334. }
  5335. if ( bAssert )
  5336. {
  5337. Assert( !"RemoveVar" );
  5338. }
  5339. }
  5340. void C_BaseEntity::CheckCLInterpChanged()
  5341. {
  5342. float flCurValue_Interp = GetClientInterpAmount();
  5343. static float flLastValue_Interp = flCurValue_Interp;
  5344. float flCurValue_InterpNPCs = cl_interp_npcs.GetFloat();
  5345. static float flLastValue_InterpNPCs = flCurValue_InterpNPCs;
  5346. if ( flLastValue_Interp != flCurValue_Interp ||
  5347. flLastValue_InterpNPCs != flCurValue_InterpNPCs )
  5348. {
  5349. flLastValue_Interp = flCurValue_Interp;
  5350. flLastValue_InterpNPCs = flCurValue_InterpNPCs;
  5351. // Tell all the existing entities to update their interpolation amounts to account for the change.
  5352. C_BaseEntityIterator iterator;
  5353. C_BaseEntity *pEnt;
  5354. while ( (pEnt = iterator.Next()) != NULL )
  5355. {
  5356. pEnt->Interp_UpdateInterpolationAmounts( pEnt->GetVarMapping() );
  5357. }
  5358. }
  5359. }
  5360. void C_BaseEntity::DontRecordInTools()
  5361. {
  5362. #ifndef NO_TOOLFRAMEWORK
  5363. m_bRecordInTools = false;
  5364. #endif
  5365. }
  5366. int C_BaseEntity::GetCreationTick() const
  5367. {
  5368. return m_nCreationTick;
  5369. }
  5370. //------------------------------------------------------------------------------
  5371. void CC_CL_Find_Ent( const CCommand& args )
  5372. {
  5373. if ( args.ArgC() < 2 )
  5374. {
  5375. Msg( "Format: cl_find_ent <substring>\n" );
  5376. return;
  5377. }
  5378. int iCount = 0;
  5379. const char *pszSubString = args[1];
  5380. Msg("Searching for client entities with classname containing substring: '%s'\n", pszSubString );
  5381. C_BaseEntity *ent = NULL;
  5382. while ( (ent = ClientEntityList().NextBaseEntity(ent)) != NULL )
  5383. {
  5384. const char *pszClassname = ent->GetClassname();
  5385. bool bMatches = false;
  5386. if ( pszClassname && pszClassname[0] )
  5387. {
  5388. if ( Q_stristr( pszClassname, pszSubString ) )
  5389. {
  5390. bMatches = true;
  5391. }
  5392. }
  5393. if ( bMatches )
  5394. {
  5395. iCount++;
  5396. Msg(" '%s' (entindex %d) %s \n", pszClassname ? pszClassname : "[NO NAME]", ent->entindex(), ent->IsDormant() ? "(DORMANT)" : "" );
  5397. }
  5398. }
  5399. Msg("Found %d matches.\n", iCount);
  5400. }
  5401. static ConCommand cl_find_ent("cl_find_ent", CC_CL_Find_Ent, "Find and list all client entities with classnames that contain the specified substring.\nFormat: cl_find_ent <substring>\n", FCVAR_CHEAT);
  5402. //------------------------------------------------------------------------------
  5403. void CC_CL_Find_Ent_Index( const CCommand& args )
  5404. {
  5405. if ( args.ArgC() < 2 )
  5406. {
  5407. Msg( "Format: cl_find_ent_index <index>\n" );
  5408. return;
  5409. }
  5410. int iIndex = atoi(args[1]);
  5411. C_BaseEntity *ent = ClientEntityList().GetBaseEntity( iIndex );
  5412. if ( ent )
  5413. {
  5414. const char *pszClassname = ent->GetClassname();
  5415. Msg(" '%s' (entindex %d) %s \n", pszClassname ? pszClassname : "[NO NAME]", iIndex, ent->IsDormant() ? "(DORMANT)" : "" );
  5416. }
  5417. else
  5418. {
  5419. Msg("Found no entity at %d.\n", iIndex);
  5420. }
  5421. }
  5422. static ConCommand cl_find_ent_index("cl_find_ent_index", CC_CL_Find_Ent_Index, "Display data for clientside entity matching specified index.\nFormat: cl_find_ent_index <index>\n", FCVAR_CHEAT);