Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7223 lines
210 KiB

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