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 edict or entity index, and do not count toward the entity limit.
TEs are unreliable and get dropped if too many are created at once. The maximum per update is 32 in multiplayer and 255 in single player.
Implementation
On the server:
- Derive from
CBaseTempEntity
inbasetempentity.h
- Create a constructor that accepts
const char *name
, and that constructsCBaseTempEntity
with the same parameter (see the example below for syntax) - Create a global 'singleton' instance to spawn further instances (see
g_TEMyEffect
in example) - Create a global function that fills in any requisite data then calls
Create( IRecipientFilter filter, float delay )
On the client:
- Derive from
C_BaseTempEntity
inc_basetempentity.h
- 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()
.
Example
Server
#include "cbase.h" #include "basetempentity.h" class CTEMyEffect : public CBaseTempEntity { DECLARE_CLASS( CTEMyEffect, CBaseTempEntity ); DECLARE_SERVERCLASS(); // Constructor CTEMyEffect( const char *name ) : CBaseTempEntity( name ) {} 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's name" ); // 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
#include "cbase.h" #include "c_basetempentity.h" class C_TEMyEffect : public C_BaseTempEntity { 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] ); } Vector m_vecPosition; }; // declare the client receive table IMPLEMENT_CLIENTCLASS_EVENT_DT(C_TEMyEffect, DT_TEMyEffect, CTEMyEffect) RecvPropVector( RECVINFO(m_vecPosition)), END_RECV_TABLE()