Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sr2echa/TF2-Source-Code/llms.txt

Use this file to discover all available pages before exploring further.

Every object in TF2 — players, projectiles, pickups, buildings — derives from CBaseEntity, declared in game/server/baseentity.h. The class implements IServerEntity and drives the networked state, think scheduling, physics collision, and the entity I/O event system that map logic relies on.

Class declaration

// game/server/baseentity.h:344
class CBaseEntity : public IServerEntity
{
public:
    DECLARE_CLASS_NOBASE( CBaseEntity );

    DECLARE_PREDICTABLE();   // client-side prediction
    DECLARE_SERVERCLASS();   // marks class for SendTable generation
    DECLARE_DATADESC();      // save/restore + entity I/O wiring
    ...
};
DECLARE_SERVERCLASS() / IMPLEMENT_SERVERCLASS_ST() generate the SendTable that the engine uses to delta-compress state to clients. Each subclass that adds network fields pairs these macros with DEFINE_SENDPROP_* entries in its .cpp file.

Networked variables

Networked fields use the CNetworkVar macro family, defined in public/networkvar.h. The underlying CNetworkVarBase<Type, Changer>::Set() calls NetworkStateChanged() whenever the value actually changes, marking the entity dirty for the next network update.
// public/networkvar.h:205
const Type& Set( const Type &val )
{
    if ( memcmp( &m_Value, &val, sizeof(Type) ) )
    {
        NetworkStateChanged();  // entity flagged for retransmit
        m_Value = val;
    }
    return m_Value;
}
Common macros and their use:
MacroUnderlying typeExample
CNetworkVar( int, m_iState )CNetworkVarBase<int>Sentry state, teleporter state
CNetworkVar( float, m_flRechargeTime )CNetworkVarBase<float>Teleporter recharge
CNetworkVar( bool, m_bDistributed )CNetworkVarBase<bool>Currency pack distributed flag
CNetworkVarEmbedded( type, name )Embedded structAggregate network objects

Entity I/O

Inputs and outputs connect entities in the map through keyvalue wiring. The inputdata_t struct carries context for every fired input:
// game/server/baseentity.h:207
struct inputdata_t
{
    CBaseEntity *pActivator;  // entity that started the event chain
    CBaseEntity *pCaller;     // entity that fired this specific output
    variant_t    value;       // typed parameter (int/float/string/vector/...)
    int          nOutputID;   // unique ID of the fired output
};
Input handlers are registered in DECLARE_DATADESC() using DEFINE_INPUTFUNC. CBaseObject for example wires:
// tf_obj.h:173
void InputSetHealth( inputdata_t &inputdata );
void InputAddHealth( inputdata_t &inputdata );
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );

Think functions

Think callbacks are scheduled per-entity using named think contexts (thinkfunc_t). Each context stores a function pointer, a tick for the next invocation, and the context name string.
// game/server/baseentity.h:325
struct thinkfunc_t
{
    BASEPTR   m_pfnThink;
    string_t  m_iszContext;
    int       m_nNextThinkTick;
    int       m_nLastThinkTick;
};
Use SetContextThink( fn, gpGlobals->curtime + delay, "ContextName" ) to schedule a named think, allowing multiple independent think callbacks on a single entity.

Entity handles

EHANDLE (CHandle<CBaseEntity>) is a safe reference type. It validates the serial number on each dereference, returning NULL if the entity has been removed — avoiding dangling pointer crashes common in raw pointer code.
typedef CHandle<CBaseEntity> EHANDLE;
Prefer EHANDLE (or typed CHandle<T>) over raw pointers when storing cross-entity references. Networked entity references use CNetworkHandle which wraps the same safety check and marks dirty on change.

Build docs developers (and LLMs) love