Temporary Entity
Temporary entities are used by the server to create short-lived or one-off effects on clients. They are different to standard entities in that they are 'fire and forget'; once one has been created, the server has nothing more to do with it. TEs have no entity handle or index and To do: confirm whether they count towards the global entity limit or not.
Implementation
On the server:
- Derive from
CBaseTempEntity
- Create a global 'singleton' instance to spawn further instances (see
g_TEMyEffect
in the example below) - Create a global function that fills in any requisite data then calls
Create( IRecipientFilter filter, float delay )
On the client:
- Derive from
C_BaseTempEntity
- Create
void PostDataUpdate( DataUpdateType_t updateType )
, which is called whenever an instance spawns
Temp entities are used quite often, also in shared game code (same code that is compiled into server.dll and client.dll). For shared code we need a shared interface that allows creating temp entities the same way on the server as on the client. This common interface is ItempEntsSystem
that provides member functions to create any temp entity. The ItempEntsSystem
interface is implemented server-side by class CTempEntsSystem
and class C_TempEntsSystem
in client code. For new temp entity classes, this interface has to be extended as well as both implementations.
For shared predicted code these classes also handle effect suppression for clients that already spawned the effect in their own prediction code. E.g.: A client fires a predicted weapon and creates instantly a local, predicted impact effect. When the server runs the same weapon code again, this impact effect must be sent to all other clients, but not to the shooting client. Filtering these temp entities that are spawned by predicted code is handled by function SuppressTE()
. See Weapon Prediction.
Example
Server
class CTEMyEffect : public CBaseTempEntity { public: DECLARE_CLASS( CTEMyEffect, CBaseTempEntity ); DECLARE_SERVERCLASS(); public: CNetworkVector( m_vecPosition ); }; // Declare server send table IMPLEMENT_SERVERCLASS_ST(CTEMyEffect, DT_TEMyEffect) SendPropVector( SENDINFO(m_vecPosition), -1, SPROP_COORD), END_SEND_TABLE() // Singleton to fire TEMyEffect objects static CTEMyEffect g_TEMyEffect ( "MyEffect" ); // global function to spawn an instance void TE_MyEffect( IRecipientFilter& filter, float delay, const Vector* position ) { // set effect data g_TEMyEffect.m_vecPosition = *position; // Send it over the wire g_TEMyEffect.Create( filter, delay ); }
Client
class C_TEMyEffect : public C_BaseTempEntity { public: DECLARE_CLASS( C_TEMyEffect, C_BaseTempEntity ); DECLARE_CLIENTCLASS(); void PostDataUpdate( DataUpdateType_t updateType ) { // temp entity has been spawned, do something Msg("Created effect at position %.1f,%.1f,%.1f\n", m_vecPosition[0], m_vecPosition[1], m_vecPosition[2] ); } public: Vector m_vecPosition; }; // declare the client receive table IMPLEMENT_CLIENTCLASS_EVENT_DT(C_TEMyEffect, DT_TEMyEffect, CTEMyEffect) RecvPropVector( RECVINFO(m_vecPosition)), END_RECV_TABLE()