|
|
//===== Copyright (c) Valve Corporation, All rights reserved. ======//
//
// Purpose: A base class for the client-side representation of entities.
//
// This class encompasses both entities that are created on the server
// and networked to the client AND entities that are created on the
// client.
//
// $NoKeywords: $
//==================================================================//
#ifndef C_BASEENTITY_H
#define C_BASEENTITY_H
#ifdef _WIN32
#pragma once
#endif
#include "mathlib/vector.h"
#include "icliententityinternal.h"
#include "engine/ivmodelrender.h"
#include "client_class.h"
#include "iclientshadowmgr.h"
#include "ehandle.h"
#include "iclientunknown.h"
#include "client_thinklist.h"
#if !defined( NO_ENTITY_PREDICTION )
#include "predictableid.h"
#endif
#include "soundflags.h"
#include "shareddefs.h"
#include "networkvar.h"
#include "sharedvar.h"
#include "tier1/interpolatedvar.h"
#include "collisionproperty.h"
#include "particle_property.h"
#include "toolframework/itoolentity.h"
#include "tier0/threadtools.h"
#include "vscript/ivscript.h"
#include "vscript_shared.h"
class C_Team; class IPhysicsObject; class IClientVehicle; class CPredictionCopy; class C_BasePlayer; struct studiohdr_t; class CStudioHdr; class CDamageModifier; class IRecipientFilter; class CUserCmd; struct solid_t; class ISave; class IRestore; class C_BaseAnimating; class C_BaseAnimatingOverlay; class C_AI_BaseNPC; struct EmitSound_t; class C_RecipientFilter; class CTakeDamageInfo; class C_BaseCombatCharacter; class CEntityMapData; class ConVar; class CClientAlphaProperty; struct CSoundParameters; class CCallQueue;
typedef unsigned int AimEntsListHandle_t;
#define INVALID_AIMENTS_LIST_HANDLE (AimEntsListHandle_t)~0
extern void RecvProxy_LocalVelocity( const CRecvProxyData *pData, void *pStruct, void *pOut );
enum CollideType_t { ENTITY_SHOULD_NOT_COLLIDE = 0, ENTITY_SHOULD_COLLIDE, ENTITY_SHOULD_RESPOND };
class VarMapEntry_t {
public: unsigned short type; unsigned short m_bNeedsToInterpolate; // Set to false when this var doesn't
// need Interpolate() called on it anymore.
void *data; IInterpolatedVar *watcher; };
struct VarMapping_t { VarMapping_t() { m_nInterpolatedEntries = 0; }
CUtlVector< VarMapEntry_t > m_Entries; int m_nInterpolatedEntries; float m_lastInterpolationTime; };
#define DECLARE_INTERPOLATION()
// How many data slots to use when in multiplayer.
#define MULTIPLAYER_BACKUP 150
struct serialentity_t;
typedef CHandle<C_BaseEntity> EHANDLE; // The client's version of EHANDLE.
typedef void (C_BaseEntity::*BASEPTR)(void); typedef void (C_BaseEntity::*ENTITYFUNCPTR)(C_BaseEntity *pOther );
// For entity creation on the client
typedef C_BaseEntity* (*DISPATCHFUNCTION)( void );
#include "touchlink.h"
#include "groundlink.h"
#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID )
//-----------------------------------------------------------------------------
// Purpose: For fully client side entities we use this information to determine
// authoritatively if the server has acknowledged creating this entity, etc.
//-----------------------------------------------------------------------------
struct PredictionContext { PredictionContext() { m_bActive = false; m_nCreationCommandNumber = -1; m_pszCreationModule = NULL; m_nCreationLineNumber = 0; m_hServerEntity = NULL; }
// The command_number of the usercmd which created this entity
bool m_bActive; int m_nCreationCommandNumber; char const *m_pszCreationModule; int m_nCreationLineNumber; // The entity to whom we are attached
CHandle< C_BaseEntity > m_hServerEntity; }; #endif
//-----------------------------------------------------------------------------
// Purpose: think contexts
//-----------------------------------------------------------------------------
struct thinkfunc_t { BASEPTR m_pfnThink; string_t m_iszContext; int m_nNextThinkTick; int m_nLastThinkTick; };
#define CREATE_PREDICTED_ENTITY( className ) \
C_BaseEntity::CreatePredictedEntityByName( className, __FILE__, __LINE__ );
// Entity flags that only exist on the client.
#define ENTCLIENTFLAG_GETTINGSHADOWRENDERBOUNDS 0x0001 // Tells us if we're getting the real ent render bounds or the shadow render bounds.
#define ENTCLIENTFLAG_DONTUSEIK 0x0002 // Don't use IK on this entity even if its model has IK.
#define ENTCLIENTFLAG_ALWAYS_INTERPOLATE 0x0004 // Used by view models.
enum entity_list_ids_t { ENTITY_LIST_INTERPOLATE = 0, ENTITY_LIST_TELEPORT, ENTITY_LIST_PRERENDER, ENTITY_LIST_SIMULATE, ENTITY_LIST_DELETE, NUM_ENTITY_LISTS };
template< typename Type > class CDiscontinuousInterpolatedVar : public CInterpolatedVar<Type> { public: explicit CDiscontinuousInterpolatedVar( const char *pDebugName = NULL ) : CInterpolatedVar<Type>(pDebugName) {
}
// Returns 1 if the value will always be the same if currentTime is always increasing.
virtual int Interpolate( float currentTime ) { int iRetVal = CInterpolatedVar<Type>::Interpolate(currentTime); if( m_Discontinuities.Count() == 0 ) { return iRetVal; }
ClearOldDiscontinuities();
float fInterpolatedTime = currentTime - this->m_InterpolationAmount;
for( int i = m_Discontinuities.Count(); --i >= 0; ) { if( m_Discontinuities[i].fBeforeTime < fInterpolatedTime ) { break; }
TransformValue( m_Discontinuities[i].matTransform, *(this->m_pValue) ); iRetVal = 0; }
return iRetVal; }
virtual void Reset( float flCurrentTime ) { CInterpolatedVar<Type>::Reset(flCurrentTime); ClearOldDiscontinuities(); }
//transforms all history prior to fDiscontinuityTime by matTransform (with the assumption that newer entries are in the new space)
//base interpolation is applied in the new space, with the inverse of matTransform applied to values interpolated to a time prior to fDiscontinuityTime
void InsertDiscontinuity( const matrix3x4_t &matTransform, float fDiscontinuityTime ) { ClearOldDiscontinuities();
TransformBefore( matTransform, fDiscontinuityTime );
int iInsertAfter; for( iInsertAfter = m_Discontinuities.Count(); --iInsertAfter >= 0; ) { if( m_Discontinuities[iInsertAfter].fBeforeTime <= fDiscontinuityTime ) break; } if( iInsertAfter < 0 ) { iInsertAfter = m_Discontinuities.AddToTail(); } else { iInsertAfter = m_Discontinuities.InsertAfter( iInsertAfter ); }
MatrixInvert( matTransform, m_Discontinuities[iInsertAfter].matTransform ); m_Discontinuities[iInsertAfter].fBeforeTime = fDiscontinuityTime; }
bool RemoveDiscontinuity( float fDiscontinuityTime, const matrix3x4_t *pFailureTransform = NULL ) { //assume the general case for this is rolling back in time for prediction
for( int i = m_Discontinuities.Count(); --i >= 0; ) { if( m_Discontinuities[i].fBeforeTime == fDiscontinuityTime ) { TransformBefore( m_Discontinuities[i].matTransform, fDiscontinuityTime ); m_Discontinuities.Remove( i ); return true; } }
if( pFailureTransform ) { TransformBefore( *pFailureTransform, fDiscontinuityTime ); } return false; }
float GetInterpolationAmount( void ) { return this->m_InterpolationAmount; } float GetInterpolatedTime( float fCurTime ) //What's the timestamp on the value we'll use.
{ float fTargetTime = fCurTime - this->m_InterpolationAmount; float fOldestEntryTime = this->GetOldestEntry(); fOldestEntryTime = MIN( fOldestEntryTime, fCurTime ); //pull entries in the future to now
return MAX( fTargetTime, fOldestEntryTime ); }
bool HasDiscontinuityForTime( float fCurTime ) { if( m_Discontinuities.Count() == 0 ) return false;
float fTargetTime = GetInterpolatedTime( fCurTime );
return ( fTargetTime < m_Discontinuities[m_Discontinuities.Count()-1].fBeforeTime ); }
bool GetDiscontinuityTransform( float fCurTime, matrix3x4_t &matOut ) { if( m_Discontinuities.Count() == 0 ) return false;
float fTargetTime = GetInterpolatedTime( fCurTime );
if( fTargetTime >= m_Discontinuities[m_Discontinuities.Count()-1].fBeforeTime ) return false;
//common case is exactly 0 or 1 transforms. 0's handled above. Do a copy of the first transform now and skip it in the iterator below
matOut = m_Discontinuities[m_Discontinuities.Count() - 1].matTransform;
matrix3x4_t matTemp; matrix3x4_t *pSwapMatrices[2] = { &matOut, &matTemp }; int iSwapRead = 0; //which of the swap indices has the newest value
for( int i = m_Discontinuities.Count() - 1; --i >= 0; ) { if( m_Discontinuities[i].fBeforeTime < fTargetTime ) { break; }
ConcatTransforms( m_Discontinuities[i].matTransform, *pSwapMatrices[iSwapRead], *pSwapMatrices[1 - iSwapRead] ); iSwapRead = 1 - iSwapRead; }
if( iSwapRead == 1 ) //matTemp has the most recent value one final copy necessary to output matrix
matOut = matTemp;
return true; }
protected: struct Discontinuity_t { matrix3x4_t matTransform; //from current space to previous space
float fBeforeTime; };
void ClearOldDiscontinuities( void ) { if( m_Discontinuities.Count() == 0 ) return;
float fOldestEntry = this->GetOldestEntry(); while( fOldestEntry >= m_Discontinuities[0].fBeforeTime ) { m_Discontinuities.Remove( 0 ); if( m_Discontinuities.Count() == 0 ) break; } }
void TransformBefore( const matrix3x4_t &matTransform, float fDiscontinuityTime ) { int iHead = this->GetHead(); if( !this->IsValidIndex( iHead ) ) return;
#ifdef _DEBUG
float fHeadTime; this->GetHistoryValue( iHead, fHeadTime ); #endif
float fTime; Type *pCurrent; int iCurrent;
iCurrent = iHead;
while( (pCurrent = this->GetHistoryValue( iCurrent, fTime )) != NULL ) { Assert( (fTime <= fHeadTime) || (iCurrent == iHead) ); //asserting that head is always newest
if( fTime < fDiscontinuityTime ) TransformValue( matTransform, *pCurrent );
iCurrent = this->GetNext( iCurrent ); if( iCurrent == iHead ) break; } }
static void TransformValue( const matrix3x4_t &matTransform, Type &Value );
CUtlVector<Discontinuity_t> m_Discontinuities; };
template<> inline void CDiscontinuousInterpolatedVar<Vector>::TransformValue( const matrix3x4_t &matTransform, Vector &Value ) { Vector vTemp = Value; VectorTransform( vTemp, matTransform, Value ); }
template<> inline void CDiscontinuousInterpolatedVar<QAngle>::TransformValue( const matrix3x4_t &matTransform, QAngle &Value ) { Value = TransformAnglesToWorldSpace( Value, matTransform ); }
//-----------------------------------------------------------------------------
// Purpose: Base client side entity object
//-----------------------------------------------------------------------------
class C_BaseEntity : public IClientEntity, public IClientModelRenderable { // Construction
DECLARE_CLASS_NOBASE( C_BaseEntity );
friend class CPrediction; friend void cc_cl_interp_all_changed( IConVar *pConVar, const char *pOldString, float flOldValue );
public: DECLARE_DATADESC(); DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); // script description
DECLARE_ENT_SCRIPTDESC();
C_BaseEntity();
protected: // Use UTIL_Remove to delete!
virtual ~C_BaseEntity();
public: static C_BaseEntity *CreatePredictedEntityByName( const char *classname, const char *module, int line, bool persist = false ); static void UpdateVisibilityAllEntities();
// FireBullets uses shared code for prediction.
virtual void FireBullets( const FireBulletsInfo_t &info ); virtual bool ShouldDrawUnderwaterBulletBubbles(); virtual bool ShouldDrawWaterImpacts( void ) { return true; } virtual bool HandleShotImpactingWater( const FireBulletsInfo_t &info, const Vector &vecEnd, ITraceFilter *pTraceFilter, Vector *pVecTracerDest ); virtual ITraceFilter* GetBeamTraceFilter( void ); virtual void DispatchTraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); virtual void DoImpactEffect( trace_t &tr, int nDamageType ); virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); virtual int GetTracerAttachment( void ); void ComputeTracerStartPosition( const Vector &vecShotSrc, Vector *pVecTracerStart ); void TraceBleed( float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType ); virtual int BloodColor(); virtual const char* GetTracerType();
// called when entity is damaged by predicted attacks
virtual void TakeDamage( const CTakeDamageInfo &info ) { }
virtual void Spawn( void ); virtual void SpawnClientEntity( void ); virtual void Precache( void ); virtual void Activate();
void ParseMapData( CEntityMapData *mapData ); virtual void OnParseMapDataFinished(); virtual bool KeyValue( const char *szKeyName, const char *szValue ); virtual bool KeyValue( const char *szKeyName, float flValue ); virtual bool KeyValue( const char *szKeyName, int nValue ); virtual bool KeyValue( const char *szKeyName, const Vector &vecValue ); virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen );
// Entities block Line-Of-Sight for NPCs by default.
// Set this to false if you want to change this behavior.
void SetBlocksLOS( bool bBlocksLOS ); bool BlocksLOS( void ); void SetAIWalkable( bool bBlocksLOS ); bool IsAIWalkable( void );
virtual void InitSharedVars( void ) {};
void Interp_SetupMappings( VarMapping_t *map ); // Returns 1 if there are no more changes (ie: we could call RemoveFromInterpolationList).
int Interp_Interpolate( VarMapping_t *map, float currentTime ); void Interp_RestoreToLastNetworked( VarMapping_t *map, int flags ); void Interp_UpdateInterpolationAmounts( VarMapping_t *map ); void Interp_HierarchyUpdateInterpolationAmounts();
// Called by the CLIENTCLASS macros.
virtual bool Init( int entnum, int iSerialNum );
// Called in the destructor to shutdown everything.
void Term();
// memory handling, uses calloc so members are zero'd out on instantiation
void *operator new( size_t stAllocateBlock ); void *operator new[]( size_t stAllocateBlock ); void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); void *operator new[]( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); void operator delete( void *pMem ); void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) { operator delete( pMem ); }
// This just picks one of the routes to IClientUnknown.
IClientUnknown* GetIClientUnknown() { return this; } virtual C_BaseAnimating* GetBaseAnimating() { return NULL; } virtual C_BaseAnimatingOverlay *GetBaseAnimatingOverlay() { return NULL; } virtual void SetClassname( const char *className );
virtual Class_T Classify( void ) { return CLASS_NONE; }
string_t m_iClassname;
HSCRIPT GetScriptInstance();
HSCRIPT m_hScriptInstance; string_t m_iszScriptId;
float m_flLastMadeNoiseTime;
// IClientUnknown overrides.
public:
virtual void SetRefEHandle( const CBaseHandle &handle ); virtual const CBaseHandle& GetRefEHandle() const;
void SetToolHandle( HTOOLHANDLE handle ); HTOOLHANDLE GetToolHandle() const;
void EnableInToolView( bool bEnable ); bool IsEnabledInToolView() const;
void SetToolRecording( bool recording ); bool IsToolRecording() const; bool HasRecordedThisFrame() const; virtual void RecordToolMessage(); virtual void OnToolStartRecording( void ) {};
// used to exclude entities from being recorded in the SFM tools
void DontRecordInTools(); bool ShouldRecordInTools() const;
protected: virtual void Release();
// IClientEntity
public: virtual ICollideable* GetCollideable() { return CollisionProp(); } virtual IClientNetworkable* GetClientNetworkable() { return this; } virtual IClientRenderable* GetClientRenderable() { return this; } virtual IClientEntity* GetIClientEntity() { return this; } virtual C_BaseEntity* GetBaseEntity() { return this; } virtual IClientThinkable* GetClientThinkable() { return this; } virtual IClientModelRenderable* GetClientModelRenderable(); virtual IClientAlphaProperty* GetClientAlphaProperty();
// Inherited from IClientModelRenderable
public: virtual bool GetRenderData( void *pData, ModelDataCategory_t nCategory );
#if 0
virtual string_t GetModelName( void ) const; #endif
// Methods of IClientRenderable
public:
virtual const Vector& GetRenderOrigin( void ); virtual const QAngle& GetRenderAngles( void ); virtual Vector GetObserverCamOrigin( void ) { return GetRenderOrigin(); } // Return the origin for player observers tracking this target
virtual const matrix3x4_t & RenderableToWorldTransform(); virtual bool IsTransparent( void ); virtual int GetRenderFlags( void ); virtual const model_t *GetModel( void ) const; virtual int DrawModel( int flags, const RenderableInstance_t &instance ); virtual bool LODTest() { return true; } // NOTE: UNUSED
virtual void GetRenderBounds( Vector& mins, Vector& maxs ); virtual IPVSNotify* GetPVSNotifyInterface(); virtual void GetRenderBoundsWorldspace( Vector& absMins, Vector& absMaxs );
virtual void GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType );
// Determine the color modulation amount
virtual void GetColorModulation( float* color );
virtual void OnThreadedDrawSetup() {} public: virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
// To mimic server call convention
C_BaseEntity *GetOwnerEntity( void ) const; void SetOwnerEntity( C_BaseEntity *pOwner );
C_BaseEntity *GetEffectEntity( void ) const; void SetEffectEntity( C_BaseEntity *pEffectEnt );
bool IsAbleToHaveFireEffect( void ) const;
// This function returns a value that scales all damage done by this entity.
// Use CDamageModifier to hook in damage modifiers on a guy.
virtual float GetAttackDamageScale( void );
// IClientNetworkable implementation.
public: virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
// save out interpolated values
virtual void PreDataUpdate( DataUpdateType_t updateType ); virtual void PostDataUpdate( DataUpdateType_t updateType ); virtual void OnDataUnchangedInPVS();
virtual void ValidateModelIndex( void );
// pvs info. NOTE: Do not override these!!
virtual void SetDormant( bool bDormant ); virtual bool IsDormant( void ) const;
virtual void OnSetDormant( bool bDormant ) {}
// Tells the entity that it's about to be destroyed due to the client receiving
// an uncompressed update that's caused it to destroy all entities & recreate them.
virtual void SetDestroyedOnRecreateEntities( void );
virtual int GetEFlags() const; virtual void SetEFlags( int iEFlags ); void AddEFlags( int nEFlagMask ); void RemoveEFlags( int nEFlagMask ); bool IsEFlagSet( int nEFlagMask ) const;
// checks to see if the entity is marked for deletion
bool IsMarkedForDeletion( void );
virtual int entindex( void ) const; // This works for client-only entities and returns the GetEntryIndex() of the entity's handle,
// so the sound system can get an IClientEntity from it.
int GetSoundSourceIndex() const;
// Server to client message received
virtual void ReceiveMessage( int classID, bf_read &msg );
virtual void* GetDataTableBasePtr();
// IClientThinkable.
public: // Called whenever you registered for a think message (with SetNextClientThink).
virtual void ClientThink();
virtual ClientThinkHandle_t GetThinkHandle(); virtual void SetThinkHandle( ClientThinkHandle_t hThink );
public:
void AddVar( void *data, IInterpolatedVar *watcher, int type, bool bSetup=false ); void RemoveVar( void *data, bool bAssert=true ); VarMapping_t* GetVarMapping();
VarMapping_t m_VarMap;
public: // An inline version the game code can use
CCollisionProperty *CollisionProp(); const CCollisionProperty*CollisionProp() const; CParticleProperty *ParticleProp(); const CParticleProperty *ParticleProp() const; CClientAlphaProperty *AlphaProp(); const CClientAlphaProperty *AlphaProp() const;
// Simply here for game shared
bool IsFloating();
virtual bool ShouldSavePhysics();
// save/restore stuff
virtual void OnSave(); virtual void OnRestore(); // capabilities for save/restore
virtual int ObjectCaps( void ); // only overload these if you have special data to serialize
virtual int Save( ISave &save ); virtual int Restore( IRestore &restore );
bool IsRenderingInFastReflections() const;
private: int SaveDataDescBlock( ISave &save, datamap_t *dmap ); int RestoreDataDescBlock( IRestore &restore, datamap_t *dmap ); bool ComputeIsRenderingInFastReflections() const;
// Client code should call this under any circumstances where fast reflection rendering type may change
void OnFastReflectionRenderingChanged(); void OnDisableShadowDepthRenderingChanged(); void OnDisableCSMRenderingChanged(); void OnShadowDepthRenderingCacheableStateChanged(); public:
// Called after spawn, and in the case of self-managing objects, after load
virtual bool CreateVPhysics();
// Convenience routines to init the vphysics simulation for this object.
// This creates a static object. Something that behaves like world geometry - solid, but never moves
IPhysicsObject *VPhysicsInitStatic( void );
// This creates a normal vphysics simulated object
IPhysicsObject *VPhysicsInitNormal( SolidType_t solidType, int nSolidFlags, bool createAsleep, solid_t *pSolid = NULL );
// This creates a vphysics object with a shadow controller that follows the AI
// Move the object to where it should be and call UpdatePhysicsShadowToCurrentPosition()
IPhysicsObject *VPhysicsInitShadow( bool allowPhysicsMovement, bool allowPhysicsRotation, solid_t *pSolid = NULL );
private: // called by all vphysics inits
bool VPhysicsInitSetup(); public:
void VPhysicsSetObject( IPhysicsObject *pPhysics ); void VPhysicsSwapObject( IPhysicsObject *pSwap ); // destroy and remove the physics object for this entity
virtual void VPhysicsDestroyObject( void );
// Purpose: My physics object has been updated, react or extract data
virtual void VPhysicsUpdate( IPhysicsObject *pPhysics ); virtual void VPhysicsShadowUpdate( IPhysicsObject *pPhysics ) {} inline IPhysicsObject *VPhysicsGetObject( void ) const { return m_pPhysicsObject; } virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); virtual bool VPhysicsIsFlesh( void ); virtual void VPhysicsCompensateForPredictionErrors( const byte *predictedFrame ); //compare your predictive data vs the server data and do something about any discrepancies.
float VPhysicsGetNonShadowMass( void ) const { return m_flNonShadowMass; }
// IClientEntity implementation.
public: virtual bool SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); virtual bool UsesFlexDelayedWeights() { return false; } virtual void DoAnimationEvents( void );
virtual const Vector& GetAbsOrigin( void ) const; virtual const QAngle& GetAbsAngles( void ) const; // see also GetVectors()
inline Vector Forward() const RESTRICT; ///< get my forward (+x) vector
inline Vector Left() const RESTRICT; ///< get my left (+y) vector
inline Vector Up() const RESTRICT; ///< get my up (+z) vector
const Vector& GetNetworkOrigin() const; const QAngle& GetNetworkAngles() const;
void SetNetworkOrigin( const Vector& org ); void SetNetworkAngles( const QAngle& ang );
const Vector& GetLocalOrigin( void ) const; void SetLocalOrigin( const Vector& origin ); vec_t GetLocalOriginDim( int iDim ) const; // You can use the X_INDEX, Y_INDEX, and Z_INDEX defines here.
void SetLocalOriginDim( int iDim, vec_t flValue );
const QAngle& GetLocalAngles( void ) const; void SetLocalAngles( const QAngle& angles ); vec_t GetLocalAnglesDim( int iDim ) const; // You can use the X_INDEX, Y_INDEX, and Z_INDEX defines here.
void SetLocalAnglesDim( int iDim, vec_t flValue );
virtual const Vector& GetPrevLocalOrigin() const; virtual const QAngle& GetPrevLocalAngles() const;
// change position, velocity, orientation instantly
// passing NULL means no change
virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
void SetLocalTransform( const matrix3x4_t &localTransform );
void SetModelName( string_t name ); string_t GetModelName( void ) const;
int GetModelIndex( void ) const; virtual void SetModelIndex( int index );
// These methods return a *world-aligned* box relative to the absorigin of the entity.
// This is used for collision purposes and is *not* guaranteed
// to surround the entire entity's visual representation
// NOTE: It is illegal to ask for the world-aligned bounds for
// SOLID_BSP objects
virtual const Vector& WorldAlignMins( ) const; virtual const Vector& WorldAlignMaxs( ) const;
// This defines collision bounds *in whatever space is currently defined by the solid type*
// SOLID_BBOX: World Align
// SOLID_OBB: Entity space
// SOLID_BSP: Entity space
// SOLID_VPHYSICS Not used
void SetCollisionBounds( const Vector& mins, const Vector &maxs );
// NOTE: These use the collision OBB to compute a reasonable center point for the entity
virtual const Vector& WorldSpaceCenter( ) const;
// FIXME: Do we want this?
const Vector& WorldAlignSize( ) const; bool IsPointSized() const;
// Returns a radius of a sphere
// *centered at the world space center* bounding the collision representation
// of the entity. NOTE: The world space center *may* move when the entity rotates.
float BoundingRadius() const;
// Used when the collision prop is told to ask game code for the world-space surrounding box
virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
// Returns the entity-to-world transform
matrix3x4_t &EntityToWorldTransform(); const matrix3x4_t &EntityToWorldTransform() const;
// Some helper methods that transform a point from entity space to world space + back
void EntityToWorldSpace( const Vector &in, Vector *pOut ) const; void WorldToEntitySpace( const Vector &in, Vector *pOut ) const;
// This function gets your parent's transform. If you're parented to an attachment,
// this calculates the attachment's transform and gives you that.
//
// You must pass in tempMatrix for scratch space - it may need to fill that in and return it instead of
// pointing you right at a variable in your parent.
matrix3x4_t& GetParentToWorldTransform( matrix3x4_t &tempMatrix );
virtual void GetVectors(Vector* forward, Vector* right, Vector* up) const;
// Sets abs angles, but also sets local angles to be appropriate
void SetAbsOrigin( const Vector& origin ); void SetAbsAngles( const QAngle& angles );
void AddFlag( int flags ); void RemoveFlag( int flagsToRemove ); void ToggleFlag( int flagToToggle ); int GetFlags( void ) const; void ClearFlags();
void SetDistanceFade( float flMinDist, float flMaxDist ); void SetGlobalFadeScale( float flFadeScale ); float GetMinFadeDist( ) const; float GetMaxFadeDist( ) const; float GetGlobalFadeScale( ) const;
MoveType_t GetMoveType( void ) const; MoveCollide_t GetMoveCollide( void ) const; virtual SolidType_t GetSolid( void ) const;
virtual int GetSolidFlags( void ) const; bool IsSolidFlagSet( int flagMask ) const; void SetSolidFlags( int nFlags ); void AddSolidFlags( int nFlags ); void RemoveSolidFlags( int nFlags ); bool IsSolid() const;
virtual class CMouthInfo *GetMouth( void );
// Retrieve sound spatialization info for the specified sound on this entity
// Return false to indicate sound is not audible
virtual bool GetSoundSpatialization( SpatializationInfo_t& info );
// Attachments
virtual int LookupAttachment( const char *pAttachmentName ) { return -1; } virtual bool GetAttachment( int number, matrix3x4_t &matrix ); virtual bool GetAttachment( int number, Vector &origin ); virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); virtual bool ComputeLightingOrigin( int nAttachmentIndex, Vector modelLightingCenter, const matrix3x4_t &matrix, Vector &transformedLightingCenter ); virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); virtual void InvalidateAttachments() {}
// Team handling
virtual C_Team *GetTeam( void ); virtual int GetTeamNumber( void ) const; virtual int GetPendingTeamNumber( void ) const; virtual void ChangeTeam( int iTeamNum ); // Assign this entity to a team.
virtual int GetRenderTeamNumber( void ); virtual bool InSameTeam( C_BaseEntity *pEntity ); // Returns true if the specified entity is on the same team as this one
virtual bool InLocalTeam( void );
// ID Target handling
virtual bool IsValidIDTarget( void ) { return false; } virtual char *GetIDString( void ) { return ""; };
// See CSoundEmitterSystem
// Will return the sound guid. If negative, the guid is unknown (call may be successful or not). 0 if the sound was not emitted. Positive if the guid is valid.
int EmitSound( const char *soundname, float soundtime = 0.0f, float *duration = NULL ); // Override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. );
int EmitSound( const char *soundname, HSOUNDSCRIPTHASH& handle, float soundtime = 0.0f, float *duration = NULL ); // Override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. );
void StopSound( const char *soundname ); void StopSound( const char *soundname, HSOUNDSCRIPTHASH& handle ); void GenderExpandString( char const *in, char *out, int maxlen );
void UpdateLastMadeNoiseTime( const char* pszSoundName = NULL );
static float GetSoundDuration( const char *soundname, char const *actormodel );
static bool GetParametersForSound( const char *soundname, CSoundParameters ¶ms, const char *actormodel ); static bool GetParametersForSound( const char *soundname, HSOUNDSCRIPTHASH& handle, CSoundParameters ¶ms, const char *actormodel );
static int EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, const Vector *pOrigin = NULL, float soundtime = 0.0f, float *duration = NULL ); static int EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, HSOUNDSCRIPTHASH& handle, const Vector *pOrigin = NULL, float soundtime = 0.0f, float *duration = NULL ); static void StopSound( int iEntIndex, const char *soundname ); static soundlevel_t LookupSoundLevel( const char *soundname ); static soundlevel_t LookupSoundLevel( const char *soundname, HSOUNDSCRIPTHASH& handle );
static int EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params ); static int EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params, HSOUNDSCRIPTHASH& handle );
static void StopSound( int iEntIndex, int iChannel, const char *pSample, bool bIsStoppingSpeakerSound = false );
static void EmitAmbientSound( int entindex, const Vector& origin, const char *soundname, int flags = 0, float soundtime = 0.0f, float *duration = NULL );
// These files need to be listed in scripts/game_sounds_manifest.txt
static HSOUNDSCRIPTHASH PrecacheScriptSound( const char *soundname ); static void PrefetchScriptSound( const char *soundname );
// For each client who appears to be a valid recipient, checks the client has disabled CC and if so, removes them from
// the recipient list.
static void RemoveRecipientsIfNotCloseCaptioning( C_RecipientFilter& filter ); static void EmitCloseCaption( IRecipientFilter& filter, int entindex, char const *token, CUtlVector< Vector >& soundorigins, float duration, bool warnifmissing = false );
// Moves all aiments into their correct position for the frame
static void MarkAimEntsDirty(); static void CalcAimEntPositions();
static bool IsPrecacheAllowed(); static void SetAllowPrecache( bool allow );
static bool m_bAllowPrecache;
static bool IsSimulatingOnAlternateTicks();
public: static bool sm_bAccurateTriggerBboxChecks; // SOLID_BBOX entities do a fully accurate trigger vs bbox check when this is set
// C_BaseEntity local functions
public:
virtual void UpdatePartitionListEntry();
// This can be used to setup the entity as a client-only entity.
// Override this to perform per-entity clientside setup
virtual bool InitializeAsClientEntity( const char *pszModelName, bool bRenderWithViewModels );
// This function gets called on all client entities once per simulation phase. If the entity
// is in the simulate list. It dispatches events like OnDataChanged()
// return false if this entity no longer needs to simulate, true otherwise
virtual bool Simulate() { return false; }
// This event is triggered during the simulation phase if an entity's data has changed. It is
// better to hook this instead of PostDataUpdate() because in PostDataUpdate(), server entity origins
// are incorrect and attachment points can't be used.
virtual void OnDataChanged( DataUpdateType_t type );
// This is called once per frame before any data is read in from the server.
virtual void OnPreDataChanged( DataUpdateType_t type );
bool IsStandable() const; bool IsBSPModel() const;
// If this is a vehicle, returns the vehicle interface
virtual IClientVehicle* GetClientVehicle() { return NULL; }
// Returns the aiment render origin + angles
virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles ); // get network origin from previous update
virtual const Vector& GetOldOrigin();
// Methods relating to traversing hierarchy
C_BaseEntity *GetMoveParent( void ) const; C_BaseEntity *GetRootMoveParent(); C_BaseEntity *FirstMoveChild( void ) const; C_BaseEntity *NextMovePeer( void ) const;
inline ClientEntityHandle_t GetClientHandle() const { return ClientEntityHandle_t( m_RefEHandle ); } inline bool IsServerEntity( void ) const;
void RenderForceOpaquePass( bool bEnable ); bool IsRenderForceOpaquePass() const; void RenderWithViewModels( bool bEnable ); bool IsRenderingWithViewModels() const; void DisableCachedRenderBounds( bool bDisabled ); bool IsCachedRenderBoundsDisabled() const;
// NOTE: The goal of this function is different from IsTranslucent().
// Here, we need to determine whether a renderable is inherently translucent
// when run-time alpha modulation or any other game code is not taken into account
virtual RenderableTranslucencyType_t ComputeTranslucencyType( ); virtual uint8 OverrideAlphaModulation( uint8 nAlpha ) { return nAlpha; } virtual uint8 OverrideShadowAlphaModulation( uint8 nAlpha ) { return nAlpha; } // Client code should call this under any circumstances where translucency type may change
void OnTranslucencyTypeChanged();
// Client code should call this under any circumstances where splitscreen rendering may change
void OnSplitscreenRenderingChanged();
virtual void GetToolRecordingState( KeyValues *msg ); virtual void CleanupToolRecordingState( KeyValues *msg );
// The value returned by here determines whether or not (and how) the entity
// is put into the spatial partition.
virtual CollideType_t GetCollideType( void );
virtual bool ShouldDraw(); inline bool IsVisible() const; inline bool IsVisibleToAnyPlayer() const; void UpdateVisibility(); // Totally sucky, but I can't think of a better way of doing this
// without changing zillions of ShouldDraw calls.
virtual bool ShouldSuppressForSplitScreenPlayer( int nSlot ) { return false; }
// Returns true if the entity changes its position every frame on the server but it doesn't
// set animtime. In that case, the client returns true here so it copies the server time to
// animtime in OnDataChanged and the position history is correct for interpolation.
virtual bool IsSelfAnimating();
// Set appropriate flags and store off data when these fields are about to change
virtual void OnLatchInterpolatedVariables( int flags ); // For predictable entities, stores last networked value
void OnStoreLastNetworkedValue();
// Initialize things given a new model.
virtual CStudioHdr *OnNewModel(); virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect ); virtual void OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect );
bool IsSimulatedEveryTick() const; bool IsAnimatedEveryTick() const; void SetSimulatedEveryTick( bool sim ); void SetAnimatedEveryTick( bool anim );
void Interp_Reset( VarMapping_t *map ); virtual void ResetLatched(); float GetInterpolationAmount( int flags ); float GetLastChangeTime( int flags );
//Get the time we would pass as an input to our interpolators
float GetEffectiveInterpolationCurTime( float currentTime );
// Interpolate the position for rendering
virtual bool Interpolate( float currentTime );
// Did the object move so far that it shouldn't interpolate?
bool Teleported( void ); // Is this a submodel of the world ( *1 etc. in name ) ( brush models only )
virtual bool IsSubModel( void ); // Deal with EF_* flags
virtual bool CreateLightEffects( void );
void AddToAimEntsList(); void RemoveFromAimEntsList();
// Reset internal fields
virtual void Clear( void ); // Helper to draw raw brush models
virtual int DrawBrushModel( bool bTranslucent, int nFlags, bool bTwoPass );
// returns the material animation start time
virtual float GetTextureAnimationStartTime(); // Indicates that a texture animation has wrapped
virtual void TextureAnimationWrapped();
// Set the next think time. Pass in CLIENT_THINK_ALWAYS to have Think() called each frame.
virtual void SetNextClientThink( float nextThinkTime );
// anything that has health can override this...
virtual void SetHealth(int iHealth) {} virtual int GetHealth() const { return 0; } virtual int GetMaxHealth() const { return 1; }
// Returns the health fraction
float HealthFraction() const;
// Should this object cast shadows?
virtual ShadowType_t ShadowCastType();
// Should this object receive shadows?
virtual bool ShouldReceiveProjectedTextures( int flags );
// Shadow-related methods
virtual bool IsShadowDirty( ); virtual void MarkShadowDirty( bool bDirty ); virtual IClientRenderable *GetShadowParent(); virtual IClientRenderable *FirstShadowChild(); virtual IClientRenderable *NextShadowPeer();
// Sets up a render handle so the leaf system will draw this entity.
void AddToLeafSystem(); void AddToLeafSystem( bool bRenderWithViewModels ); // remove entity form leaf system again
void RemoveFromLeafSystem();
// A method to apply a decal to an entity
virtual void AddDecal( const Vector& rayStart, const Vector& rayEnd, const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS, const Vector *saxis = NULL, int nAdditionalDecalFlags = 0 ); // A method to remove all decals from an entity
void RemoveAllDecals( void );
// Is this a brush model?
bool IsBrushModel() const;
// A random value 0-1 used by proxies to make sure they're not all in sync
float ProxyRandomValue() const { return m_flProxyRandomValue; } void SetProxyRandomValue( float flNewValue ) { m_flProxyRandomValue = flNewValue; }
// The spawn time of this entity
float SpawnTime() const { return m_flSpawnTime; }
virtual bool IsClientCreated( void ) const;
virtual void UpdateOnRemove( void );
virtual void SUB_Remove( void );
// Prediction stuff
/////////////////
void CheckInitPredictable( const char *context ); void CheckShutdownPredictable( const char *context ); virtual C_BasePlayer *GetPredictionOwner( void );
void AllocateIntermediateData( void ); void DestroyIntermediateData( void ); void ShiftIntermediateDataForward( int slots_to_remove, int previous_last_slot ); void ShiftFirstPredictedIntermediateDataForward( int slots_to_remove ); void ShiftIntermediateData_TickAdjust( int delta, int last_slot );
void *GetPredictedFrame( int framenumber ); void *GetFirstPredictedFrame( int framenumber ); //similar to GetPredictedFrame() but only stores the results from the first prediction of each command
void GetUnacknowledgedPredictedFrameRange( int &iStart, int &iEnd ); //Get the range of predicted frames we may restore from at any moment.
void *GetOriginalNetworkDataObject( void ); bool IsIntermediateDataAllocated( void ) const;
virtual void InitPredictable( C_BasePlayer *pOwner ); void ShutdownPredictable( void ); int GetSplitUserPlayerPredictionSlot();
virtual void SetPredictable( bool state ); bool GetPredictable( void ) const; void PreEntityPacketReceived( int commands_acknowledged ); void PostEntityPacketReceived( void ); bool PostNetworkDataReceived( int commands_acknowledged ); virtual void HandlePredictionError( bool bErrorInThisEntity ); //we just processed a network update with errors, bErrorInThisEntity is false if the prediction errors were entirely in other entities and not this one
virtual bool PredictionErrorShouldResetLatchedForAllPredictables( void ) { return true; } //legacy behavior is that any prediction error causes all predictables to reset latched
virtual bool PredictionIsPhysicallySimulated( void ) { return false; } //by default, all prediction is driven by player commands, return true if your prediction is based on server simulation ticks
bool GetPredictionEligible( void ) const; void SetPredictionEligible( bool canpredict );
enum { SLOT_ORIGINALDATA = -1, };
void SaveData( const char *context, int slot, int type ); void RestoreData( const char *context, int slot, int type );
// Called after restoring data into prediction slots. This function is used in place of proxies
// on the variables, so if some variable like m_nModelIndex needs to update other state (like
// the model pointer), it is done here.
void OnPostRestoreData();
virtual char const * DamageDecal( int bitsDamageType, int gameMaterial ); virtual void DecalTrace( trace_t *pTrace, char const *decalName ); virtual void ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName );
virtual bool ShouldPredict( void ) { return false; }; // interface function pointers
union{ // Doing this lame union to force the compiler to properly align the
// member function pointer to at least 16-bytes for warning control.
void (C_BaseEntity::*m_pfnThink)(void); char __dont_use_me_pad[16]; }; virtual void Think( void ) { AssertMsg( m_pfnThink != &C_BaseEntity::Think, "Infinite recursion is infinitely bad." );
if ( m_pfnThink ) { ( this->*m_pfnThink )(); } }
void PhysicsDispatchThink( BASEPTR thinkFunc ); // Toggle the visualization of the entity's abs/bbox
enum { VISUALIZE_COLLISION_BOUNDS = 0x1, VISUALIZE_SURROUNDING_BOUNDS = 0x2, VISUALIZE_RENDER_BOUNDS = 0x4, };
void ClearBBoxVisualization( void ); void ToggleBBoxVisualization( int fVisFlags ); void DrawBBoxVisualizations( void );
virtual bool PreRender( int nSplitScreenPlayerSlot );
bool IsViewEntity() const;
// Methods implemented on both client and server
public: void SetSize( const Vector &vecMin, const Vector &vecMax ); // UTIL_SetSize( pev, mins, maxs );
virtual char const *GetClassname( void ); char const *GetDebugName( void ); virtual const char *GetPlayerName() const { return NULL; } static int PrecacheModel( const char *name ); static bool PrecacheSound( const char *name ); static void PrefetchSound( const char *name ); void Remove( ); // UTIL_Remove( this );
#ifdef PORTAL2
const char *GetSignifierName( void ); #endif // PORTAL2
public:
// Returns the attachment point index on our parent that our transform is relative to.
// 0 if we're relative to the parent's absorigin and absangles.
unsigned char GetParentAttachment() const;
// Externalized data objects ( see sharreddefs.h for DataObjectType_t )
bool HasDataObjectType( int type ) const; void AddDataObjectType( int type ); void RemoveDataObjectType( int type );
void *GetDataObject( int type ); void *CreateDataObject( int type ); void DestroyDataObject( int type ); void DestroyAllDataObjects( void );
// Determine approximate velocity based on updates from server
virtual void EstimateAbsVelocity( Vector& vel );
#if !defined( NO_ENTITY_PREDICTION )
// The player drives simulation of this entity
void SetPlayerSimulated( C_BasePlayer *pOwner ); bool IsPlayerSimulated( void ) const; CBasePlayer *GetSimulatingPlayer( void ); void UnsetPlayerSimulated( void ); #endif
// Sorry folks, here lies TF2-specific stuff that really has no other place to go
virtual bool CanBePoweredUp( void ) { return false; } virtual bool AttemptToPowerup( int iPowerup, float flTime, float flAmount = 0, C_BaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL ) { return false; }
void SetCheckUntouch( bool check ); bool GetCheckUntouch() const;
virtual bool IsCurrentlyTouching( void ) const;
virtual void StartTouch( C_BaseEntity *pOther ); virtual void Touch( C_BaseEntity *pOther ); virtual void EndTouch( C_BaseEntity *pOther );
void (C_BaseEntity ::*m_pfnTouch)( C_BaseEntity *pOther );
void PhysicsStep( void );
protected: static bool sm_bDisableTouchFuncs; // Disables PhysicsTouch and PhysicsStartTouch function calls
bool m_bIsAutoaimTarget;
public: touchlink_t *PhysicsMarkEntityAsTouched( C_BaseEntity *other ); void PhysicsTouch( C_BaseEntity *pentOther ); void PhysicsStartTouch( C_BaseEntity *pentOther );
// HACKHACK:Get the trace_t from the last physics touch call (replaces the even-hackier global trace vars)
static const trace_t &GetTouchTrace( void );
// FIXME: Should be private, but I can't make em private just yet
void PhysicsImpact( C_BaseEntity *other, trace_t &trace ); void PhysicsMarkEntitiesAsTouching( C_BaseEntity *other, trace_t &trace ); void PhysicsMarkEntitiesAsTouchingEventDriven( C_BaseEntity *other, trace_t &trace ); void PhysicsTouchTriggers( const Vector *pPrevAbsOrigin = NULL );
// Physics helper
static void PhysicsRemoveTouchedList( C_BaseEntity *ent ); static void PhysicsNotifyOtherOfUntouch( C_BaseEntity *ent, C_BaseEntity *other ); static void PhysicsRemoveToucher( C_BaseEntity *other, touchlink_t *link );
groundlink_t *AddEntityToGroundList( CBaseEntity *other ); void PhysicsStartGroundContact( CBaseEntity *pentOther );
static void PhysicsNotifyOtherOfGroundRemoval( CBaseEntity *ent, CBaseEntity *other ); static void PhysicsRemoveGround( CBaseEntity *other, groundlink_t *link ); static void PhysicsRemoveGroundList( CBaseEntity *ent );
void StartGroundContact( CBaseEntity *ground ); void EndGroundContact( CBaseEntity *ground );
void SetGroundChangeTime( float flTime ); float GetGroundChangeTime( void );
// Remove this as ground entity for all object resting on this object
void WakeRestingObjects(); bool HasNPCsOnIt();
bool PhysicsCheckWater( void ); void PhysicsCheckVelocity( void ); void PhysicsAddHalfGravity( float timestep ); void PhysicsAddGravityMove( Vector &move );
virtual unsigned int PhysicsSolidMaskForEntity( void ) const;
void SetGroundEntity( C_BaseEntity *ground ); C_BaseEntity *GetGroundEntity( void ); C_BaseEntity *GetGroundEntity( void ) const { return const_cast<C_BaseEntity *>(this)->GetGroundEntity(); }
void PhysicsPushEntity( const Vector& push, trace_t *pTrace ); void PhysicsCheckWaterTransition( void );
// Performs the collision resolution for fliers.
void PerformFlyCollisionResolution( trace_t &trace, Vector &move ); void ResolveFlyCollisionBounce( trace_t &trace, Vector &vecVelocity, float flMinTotalElasticity = 0.0f ); void ResolveFlyCollisionSlide( trace_t &trace, Vector &vecVelocity ); void ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity );
void PhysicsCheckForEntityUntouch( void );
// Creates the shadow (if it doesn't already exist) based on shadow cast type
void CreateShadow();
// Destroys the shadow; causes its type to be recomputed if the entity doesn't go away immediately.
void DestroyShadow();
protected: // think function handling
enum thinkmethods_t { THINK_FIRE_ALL_FUNCTIONS, THINK_FIRE_BASE_ONLY, THINK_FIRE_ALL_BUT_BASE, }; public:
// Unlinks from hierarchy
// Set the movement parent. Your local origin and angles will become relative to this parent.
// If iAttachment is a valid attachment on the parent, then your local origin and angles
// are relative to the attachment on this entity.
void SetParent( C_BaseEntity *pParentEntity, int iParentAttachment=0 );
bool PhysicsRunThink( thinkmethods_t thinkMethod = THINK_FIRE_ALL_FUNCTIONS ); bool PhysicsRunSpecificThink( int nContextIndex, BASEPTR thinkFunc );
virtual void PhysicsSimulate( void ); virtual bool IsAlive( void )const;
bool IsInWorld( void ) { return true; }
bool IsWorld() const { return entindex() == 0; } /////////////////
virtual bool ShouldRegenerateOriginFromCellBits() const;
virtual bool IsPlayer( void ) const { return false; }; virtual bool IsWeaponWorldModel( void ) const { return false; }; virtual bool IsBaseCombatCharacter( void ) { return false; }; //virtual bool IsGrenadeProjectile( void ) { return false; };
virtual C_BaseCombatCharacter *MyCombatCharacterPointer( void ) { return NULL; } virtual bool IsNPC( void ) { return false; } C_AI_BaseNPC *MyNPCPointer( void );
virtual bool IsSprite( void ) const { return false; } virtual bool IsProp( void ) const { return false; }
// TF2 specific
virtual bool IsBaseObject( void ) const { return false; } virtual bool IsBaseCombatWeapon( void ) const { return false; } virtual class C_BaseCombatWeapon *MyCombatWeaponPointer() { return NULL; }
// Entities like the player, weapon models, and view models have special logic per-view port related to visibility and the model to be used, etc.
virtual bool ShouldDrawForSplitScreenUser( int nSlot ); void SetBlurState( bool bShouldBlur ); virtual bool IsBlurred( void );
virtual bool IsBaseTrain( void ) const { return false; }
// Returns the eye point + angles (used for viewing + shooting)
virtual Vector EyePosition( void ); virtual const QAngle& EyeAngles( void ); // Direction of eyes
virtual const QAngle& LocalEyeAngles( void ); // Direction of eyes in local space (pl.v_angle)
// position of ears
virtual Vector EarPosition( void );
Vector EyePosition( void ) const; // position of eyes
const QAngle &EyeAngles( void ) const; // Direction of eyes in world space
const QAngle &LocalEyeAngles( void ) const; // Direction of eyes
Vector EarPosition( void ) const; // position of ears
// Called by physics to see if we should avoid a collision test....
virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
// Sets physics parameters
void SetFriction( float flFriction );
void SetGravity( float flGravity ); float GetGravity( void ) const;
// Sets the model from a model index
void SetModelByIndex( int nModelIndex );
// Set model... (NOTE: Should only be used by client-only entities
// Returns false if the model name is bogus
bool SetModel( const char *pModelName );
virtual void SetModelPointer( const model_t *pModel );
// Access movetype and solid.
void SetMoveType( MoveType_t val, MoveCollide_t moveCollide = MOVECOLLIDE_DEFAULT ); // Set to one of the MOVETYPE_ defines.
void SetMoveCollide( MoveCollide_t val ); // Set to one of the MOVECOLLIDE_ defines.
void SetSolid( SolidType_t val ); // Set to one of the SOLID_ defines.
// NOTE: Setting the abs velocity in either space will cause a recomputation
// in the other space, so setting the abs velocity will also set the local vel
void SetLocalVelocity( const Vector &vecVelocity ); void SetAbsVelocity( const Vector &vecVelocity ); const Vector& GetLocalVelocity() const; const Vector& GetAbsVelocity( ) const;
void ApplyLocalVelocityImpulse( const Vector &vecImpulse ); void ApplyAbsVelocityImpulse( const Vector &vecImpulse ); void ApplyLocalAngularVelocityImpulse( const AngularImpulse &angImpulse );
// NOTE: Setting the abs velocity in either space will cause a recomputation
// in the other space, so setting the abs velocity will also set the local vel
void SetLocalAngularVelocity( const QAngle &vecAngVelocity ); const QAngle& GetLocalAngularVelocity( ) const;
// void SetAbsAngularVelocity( const QAngle &vecAngAbsVelocity );
// const QAngle& GetAbsAngularVelocity( ) const;
const Vector& GetBaseVelocity() const; void SetBaseVelocity( const Vector& v );
virtual const Vector &GetViewOffset() const; virtual void SetViewOffset( const Vector& v );
virtual void GetGroundVelocityToApply( Vector &vecGroundVel ) { vecGroundVel = vec3_origin; }
// Invalidates the abs state of all children
void InvalidatePhysicsRecursive( int nChangeFlags );
ClientRenderHandle_t GetRenderHandle() const;
void SetRemovalFlag( bool bRemove );
bool HasSpawnFlags( int nFlags ) const;
// Effects...
bool IsEffectActive( int nEffectMask ) const; void AddEffects( int nEffects ); void RemoveEffects( int nEffects ); int GetEffects( void ) const; void ClearEffects( void ); void SetEffects( int nEffects );
// Computes the abs position of a point specified in local space
void ComputeAbsPosition( const Vector &vecLocalPosition, Vector *pAbsPosition );
// Computes the abs position of a direction specified in local space
void ComputeAbsDirection( const Vector &vecLocalDirection, Vector *pAbsDirection );
// These methods encapsulate MOVETYPE_FOLLOW, which became obsolete
void FollowEntity( CBaseEntity *pBaseEntity, bool bBoneMerge = true ); void StopFollowingEntity( ); // will also change to MOVETYPE_NONE
virtual bool IsFollowingEntity(); CBaseEntity *GetFollowedEntity();
// For shadows rendering the correct body + sequence...
virtual int GetBody() { return 0; } virtual int GetSkin() { return 0; }
const Vector &ScriptGetForward( void ) { static Vector vecForward; GetVectors( &vecForward, NULL, NULL ); return vecForward; } const Vector &ScriptGetLeft( void ) { static Vector vecLeft; GetVectors( NULL, &vecLeft, NULL ); return vecLeft; } const Vector &ScriptGetUp( void ) { static Vector vecUp; GetVectors( NULL, NULL, &vecUp ); return vecUp; }
// Stubs on client
void NetworkStateManualMode( bool activate ) { } void NetworkStateChanged() { } void NetworkStateChanged( void *pVar ) { } void NetworkStateSetUpdateInterval( float N ) { } void NetworkStateForceUpdate() { }
// Think functions with contexts
int RegisterThinkContext( const char *szContext ); BASEPTR ThinkSet( BASEPTR func, float flNextThinkTime = 0, const char *szContext = NULL ); void SetNextThink( float nextThinkTime, const char *szContext = NULL ); float GetNextThink( const char *szContext = NULL ); float GetLastThink( const char *szContext = NULL ); int GetNextThinkTick( const char *szContext = NULL ); int GetLastThinkTick( const char *szContext = NULL ); // These set entity flags (EFL_*) to help optimize queries
void CheckHasThinkFunction( bool isThinkingHint = false ); void CheckHasGamePhysicsSimulation(); bool WillThink(); bool WillSimulateGamePhysics(); int GetFirstThinkTick(); // get first tick thinking on any context
float GetAnimTime() const; void SetAnimTime( float at );
float GetSimulationTime() const; void SetSimulationTime( float st );
#if defined(ENABLE_CREATE_TIME)
float GetCreateTime() { return m_flCreateTime; } void SetCreateTime( float flCreateTime ) { m_flCreateTime = flCreateTime; } #endif
int GetCreationTick() const;
#ifdef _DEBUG
void FunctionCheck( inputfunc_t pFunction, const char *name );
ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) { //COMPILE_TIME_ASSERT( sizeof(func) == 4 ? 8 );
m_pfnTouch = func; //FunctionCheck( reinterpret_cast<inputfunc_t>(m_pfnTouch), name );
return func; } #endif
// Gets the model instance + shadow handle
virtual ModelInstanceHandle_t GetModelInstance() { return m_ModelInstance; } void SetModelInstance( ModelInstanceHandle_t hInstance) { m_ModelInstance = hInstance; } bool SnatchModelInstance( C_BaseEntity * pToEntity ); virtual ClientShadowHandle_t GetShadowHandle() const { return m_ShadowHandle; } virtual ClientRenderHandle_t& RenderHandle();
void CreateModelInstance();
// Sets the origin + angles to match the last position received
void MoveToLastReceivedPosition( bool force = false );
bool IsAutoaimTarget( void ) const;
protected: // Only meant to be called from subclasses
void DestroyModelInstance();
// Interpolate entity
static void ProcessTeleportList(); static void ProcessInterpolatedList(); static void CheckInterpolatedVarParanoidMeasurement();
// overrideable rules if an entity should interpolate
virtual bool ShouldInterpolate();
// Call this in OnDataChanged if you don't chain it down!
void MarkMessageReceived();
// Gets the last message time
float GetLastMessageTime() const { return m_flLastMessageTime; }
// For non-players
int PhysicsClipVelocity (const Vector& in, const Vector& normal, Vector& out, float overbounce );
protected: // Two part guts of Interpolate(). Shared with C_BaseAnimating.
enum { INTERPOLATE_STOP=0, INTERPOLATE_CONTINUE };
// Returns INTERPOLATE_STOP or INTERPOLATE_CONTINUE.
// bNoMoreChanges is set to 1 if you can call RemoveFromInterpolationList on the entity.
int BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QAngle &oldAngles, int &bNoMoreChanges ); void BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, int nChangeFlags );
public: // Accessors for above
static int GetPredictionRandomSeed( void ); static void SetPredictionRandomSeed( const CUserCmd *cmd ); static C_BasePlayer *GetPredictionPlayer( void ); static void SetPredictionPlayer( C_BasePlayer *player ); static void CheckCLInterpChanged();
// Collision group accessors
int GetCollisionGroup() const; void SetCollisionGroup( int collisionGroup ); void CollisionRulesChanged();
static C_BaseEntity *Instance( int iEnt ); // Doesn't do much, but helps with trace results
static C_BaseEntity *Instance( IClientEntity *ent ); static C_BaseEntity *Instance( CBaseHandle hEnt ); // For debugging shared code
static bool IsServer( void ); static bool IsClient( void ); static char const *GetDLLType( void ); static void SetAbsQueriesValid( bool bValid ); static bool IsAbsQueriesValid( void );
// Enable/disable abs recomputations on a stack.
static void PushEnableAbsRecomputations( bool bEnable ); static void PopEnableAbsRecomputations();
// This requires the abs recomputation stack to be empty and just sets the global state.
// It should only be used at the scope of the frame loop.
static void EnableAbsRecomputations( bool bEnable ); static bool IsAbsRecomputationsEnabled( void );
static void PreRenderEntities( int nSplitScreenPlayerSlot ); static void PurgeRemovedEntities(); static void SimulateEntities();
//A queue that processes after we simulate all client entities. For operations that modify the simulate list (portal ghostrenderables)
static CCallQueue * GetSimulateCallQueue( void );
// Bloat the culling bbox past the parent ent's bbox in local space if EF_BONEMERGE_FASTCULL is set.
virtual void BoneMergeFastCullBloat( Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs ) const;
// Accessors for color.
const color24 GetRenderColor() const; byte GetRenderColorR() const; byte GetRenderColorG() const; byte GetRenderColorB() const; byte GetRenderAlpha() const; void SetRenderColor( byte r, byte g, byte b ); void SetRenderColorR( byte r ); void SetRenderColorG( byte g ); void SetRenderColorB( byte b ); void SetRenderAlpha( byte a );
void SetRenderMode( RenderMode_t nRenderMode, bool bForceUpdate = false ); RenderMode_t GetRenderMode() const;
void SetRenderFX( RenderFx_t nRenderFX, float flStartTime = FLT_MAX, float flDuration = 0.0f ); RenderFx_t GetRenderFX() const;
// Returns true if there was a change.
bool SetCellBits( int cellbits = CELL_BASEENTITY_ORIGIN_CELL_BITS );
static void RecvProxy_CellBits( const CRecvProxyData *pData, void *pStruct, void *pOut ); static void RecvProxy_CellX( const CRecvProxyData *pData, void *pStruct, void *pOut ); static void RecvProxy_CellY( const CRecvProxyData *pData, void *pStruct, void *pOut ); static void RecvProxy_CellZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); static void RecvProxy_CellOrigin( const CRecvProxyData *pData, void *pStruct, void *pOut ); static void RecvProxy_CellOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ); static void RecvProxy_CellOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); static void RecvProxyOldSpottedByMask( const CRecvProxyData *pData, void *pStruct, void *pOut );
const char *GetEntityName();
public:
// Determine what entity this corresponds to
int index;
// Entity flags that are only for the client (ENTCLIENTFLAG_ defines).
unsigned short m_EntClientFlags;
private: // Model for rendering
const model_t *model; CNetworkColor32( m_clrRender );
public: protected: // Cell data is available to derived classes for RecvProxy issues
int m_cellbits; int m_cellwidth; int m_cellX; int m_cellY; int m_cellZ; Vector m_vecCellOrigin; // cached cell offset position
// BEGIN PREDICTION DATA COMPACTION (these fields are together to allow for faster copying in prediction system)
// FTYPEDESC_INSENDTABLE STUFF
private: Vector m_vecAbsVelocity; Vector m_vecAbsOrigin; Vector m_vecOrigin;
QAngle m_vecAngVelocity; QAngle m_angAbsRotation; QAngle m_angRotation;
float m_flGravity; // A random value used by material proxies for each model instance.
float m_flProxyRandomValue;
int m_iEFlags; // entity flags EFL_*
unsigned char m_nWaterType; // For client/server entities, true if the entity goes outside the PVS.
// Unused for client only entities.
bool m_bDormant;
bool m_bCanUseBrushModelFastPath;
// FTYPEDESC_INSENDTABLE STUFF (end)
private: // Effects to apply
int m_fEffects; public: // Team Handling
int m_iTeamNum; int m_iPendingTeamNum; int m_nNextThinkTick; int m_iHealth; private: int m_fFlags; // Behavior flags
protected: // Object eye position
Vector m_vecViewOffset; private: // Object velocity
Vector m_vecVelocity; Vector m_vecBaseVelocity; // Base velocity
QAngle m_angNetworkAngles;
// Last values to come over the wire. Used for interpolation.
Vector m_vecNetworkOrigin;
// Friction.
float m_flFriction;
// The moveparent received from networking data
CHandle<C_BaseEntity> m_hNetworkMoveParent; // The owner!
EHANDLE m_hOwnerEntity; EHANDLE m_hGroundEntity;
char m_iName[MAX_PATH];
#ifdef PORTAL2
char m_iSignifierName[MAX_PATH]; #endif // PORTAL2
public: // Object model index
short m_nModelIndex; private: unsigned char m_nRenderFX; unsigned char m_nRenderMode; unsigned char m_MoveType; unsigned char m_MoveCollide; unsigned char m_nWaterLevel;
public: char m_lifeState;
// END PREDICTION DATA COMPACTION
public:
public: // Time animation sequence or frame was last changed
float m_flAnimTime; float m_flOldAnimTime;
float m_flSimulationTime; float m_flOldSimulationTime; #if defined(ENABLE_CREATE_TIME)
float m_flCreateTime; #endif
private: unsigned char m_nOldRenderMode;
public: // Used to store the state we were added to the BSP as, so it can
// reinsert the entity if the state changes.
ClientRenderHandle_t m_hRender; // link into spatial partition
CBitVec< MAX_SPLITSCREEN_PLAYERS > m_VisibilityBits;
// Interpolation says don't draw yet
bool m_bReadyToDraw; bool m_bClientSideRagdoll;
// Should we be interpolating?
static bool IsInterpolationEnabled();
//
int m_nLastThinkTick;
char m_takedamage;
// was pev->speed
float m_flSpeed;
// Certain entities (projectiles) can be created on the client
#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID )
CPredictableId m_PredictableID; PredictionContext *m_pPredictionContext; #endif
// used so we know when things are no longer touching
int touchStamp;
// Called after predicted entity has been acknowledged so that no longer needed entity can
// be deleted
// Return true to force deletion right now, regardless of isbeingremoved
virtual bool OnPredictedEntityRemove( bool isbeingremoved, C_BaseEntity *predicted );
bool IsDormantPredictable( void ) const; bool BecameDormantThisPacket( void ) const; void SetDormantPredictable( bool dormant );
int GetWaterLevel() const; void SetWaterLevel( int nLevel ); int GetWaterType() const; void SetWaterType( int nType );
float GetElasticity( void ) const;
int GetTextureFrameIndex( void ); void SetTextureFrameIndex( int iIndex );
virtual bool GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const; virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const; virtual C_BaseEntity *GetShadowUseOtherEntity( void ) const; virtual void SetShadowUseOtherEntity( C_BaseEntity *pEntity );
CDiscontinuousInterpolatedVar< QAngle >& GetRotationInterpolator(); CDiscontinuousInterpolatedVar< Vector >& GetOriginInterpolator(); virtual bool AddRagdollToFadeQueue( void ) { return true; }
// Dirty bits
void MarkRenderHandleDirty();
// used by SourceTV since move-parents may be missing when child spawns.
void HierarchyUpdateMoveParent();
void SetCPULevels( int nMinCPULevel, int nMaxCPULevel ); void SetGPULevels( int nMinGPULevel, int nMaxGPULevel ); int GetMinCPULevel( ) const; int GetMaxCPULevel( ) const; int GetMinGPULevel( ) const; int GetMaxGPULevel( ) const;
#if defined ( PORTAL2 )
int GetServerObjectCaps() { return m_iObjectCapsCache; } #endif
protected: // FIXME: Should I move the functions handling these out of C_ClientEntity
// and into C_BaseEntity? Then we could make these private.
// Client handle
CBaseHandle m_RefEHandle; // Reference ehandle. Used to generate ehandles off this entity.
private: // Set by tools if this entity should route "info" to various tools listening to HTOOLENTITIES
#ifndef NO_TOOLFRAMEWORK
bool m_bEnabledInToolView; bool m_bToolRecording; HTOOLHANDLE m_ToolHandle; int m_nLastRecordedFrame; bool m_bRecordInTools; // should this entity be recorded in the tools (we exclude some things like models for menus)
#endif
protected: // pointer to the entity's physics object (vphysics.dll)
IPhysicsObject *m_pPhysicsObject; float m_flNonShadowMass; // cached mass (shadow controllers set mass to VPHYSICS_MAX_MASS, or 50000)
#if !defined( NO_ENTITY_PREDICTION )
bool m_bPredictionEligible; #endif
int m_nSimulationTick;
// Think contexts
int GetIndexForThinkContext( const char *pszContext ); CUtlVector< thinkfunc_t > m_aThinkFunctions; int m_iCurrentThinkContext;
int m_spawnflags;
// Allow studio models to tell us what their m_nBody value is
virtual int GetStudioBody( void ) { return 0; } // call this in postdataupdate to detect hierarchy changes
bool IsParentChanging();
#if defined ( PORTAL2 )
// Received caps from server. Using this for +use validity checking.
int m_iObjectCapsCache; #endif
private: friend void OnRenderStart();
// This can be used to setup the entity as a client-only entity. It gets an entity handle,
// a render handle, and is put into the spatial partition.
bool InitializeAsClientEntityByIndex( int iIndex, bool bRenderWithViewModels );
// Figure out the smoothly interpolated origin for all server entities. Happens right before
// letting all entities simulate.
static void InterpolateServerEntities(); // Check which entities want to be drawn and add them to the leaf system.
static void AddVisibleEntities();
// For entities marked for recording, post bone messages to IToolSystems
static void ToolRecordEntities();
// Computes the base velocity
void UpdateBaseVelocity( void );
// Physics-related private methods
void PhysicsPusher( void ); void PhysicsNone( void ); void PhysicsNoclip( void ); void PhysicsParent( void ); void PhysicsStepRunTimestep( float timestep ); void PhysicsToss( void ); void PhysicsCustom( void );
// Simulation in local space of rigid children
void PhysicsRigidChild( void );
// Computes absolute position based on hierarchy
void CalcAbsolutePosition( ); void CalcAbsoluteVelocity();
// Computes new angles based on the angular velocity
void SimulateAngles( float flFrameTime );
// Implement this if you use MOVETYPE_CUSTOM
virtual void PerformCustomPhysics( Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity );
// methods related to decal adding
void AddStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS, int nAdditionalDecalFlags = 0 ); void AddBrushModelDecal( const Ray_t& ray, const Vector& decalCenter, int decalIndex, bool doTrace, trace_t& tr, const Vector *saxis = NULL, int nAdditionalDecalFlags = 0 ); public: void AddStudioMaterialDecal( const Ray_t& ray, IMaterial *pDecalMaterial, float flInputRadius, Vector vec_up );
const float GetUseLookAtAngle( void ) { return m_flUseLookAtAngle; } private:
void ComputePackedOffsets( void ); int GetIntermediateDataSize( void );
void UnlinkChild( C_BaseEntity *pParent, C_BaseEntity *pChild ); void LinkChild( C_BaseEntity *pParent, C_BaseEntity *pChild ); void HierarchySetParent( C_BaseEntity *pNewParent ); void UnlinkFromHierarchy();
// Computes the water level + type
void UpdateWaterState();
// Checks a sweep without actually performing the move
void PhysicsCheckSweep( const Vector& vecAbsStart, const Vector &vecAbsDelta, trace_t *pTrace );
// FIXME: REMOVE!!!
void MoveToAimEnt( ); // Sets/Gets the next think based on context index
void SetNextThink( int nContextIndex, float thinkTime ); void SetLastThink( int nContextIndex, float thinkTime ); float GetNextThink( int nContextIndex ) const; int GetNextThinkTick( int nContextIndex ) const;
void CleanUpAlphaProperty();
float m_flUseLookAtAngle;
#if !defined( NO_ENTITY_PREDICTION )
// It's still in the list for "fixup purposes" and simulation, but don't try to render it any more...
bool m_bDormantPredictable;
// So we can clean it up
int m_nIncomingPacketEntityBecameDormant; #endif
// The spawn time of the entity
float m_flSpawnTime;
// Timestamp of message arrival
float m_flLastMessageTime;
// Model instance data..
ModelInstanceHandle_t m_ModelInstance;
// Shadow data
ClientShadowHandle_t m_ShadowHandle; CBitVec< MAX_SPLITSCREEN_PLAYERS > m_ShadowBits; // Per-splitscreen user shadow visibility bits
ClientThinkHandle_t m_hThink;
unsigned char m_iParentAttachment; // 0 if we're relative to the parent's absorigin and absangles.
unsigned char m_iOldParentAttachment;
// Prediction system
bool m_bPredictable; bool m_bRenderWithViewModels; bool m_bDisableCachedRenderBounds; protected: // NOTE: This is a hack for portal2. There is a piece of networking code in OnDataChangedInPVS() that slams m_flSimulationTime
// this causes interpolation bugs on remote players in p2
bool m_bDisableSimulationFix;
// Fades
float m_fadeMinDist; float m_fadeMaxDist; float m_flFadeScale;
public:
void OnSimulationTimeChanging( float flPreviousSimulationTime, float flNextSimulationTime );
private: int m_nSplitUserPlayerPredictionSlot;
// Hierarchy
CHandle<C_BaseEntity> m_pMoveParent; CHandle<C_BaseEntity> m_pMoveChild; CHandle<C_BaseEntity> m_pMovePeer; CHandle<C_BaseEntity> m_pMovePrevPeer; CHandle<C_BaseEntity> m_hOldMoveParent;
string_t m_ModelName;
CNetworkVarEmbedded( CCollisionProperty, m_Collision ); CNetworkVarEmbedded( CParticleProperty, m_Particles ); CClientAlphaProperty *m_pClientAlphaProperty;
// Physics state
float m_flElasticity;
float m_flShadowCastDistance; EHANDLE m_ShadowDirUseOtherEntity;
float m_flGroundChangeTime;
Vector m_vecOldOrigin; QAngle m_vecOldAngRotation;
CDiscontinuousInterpolatedVar< Vector > m_iv_vecOrigin; CDiscontinuousInterpolatedVar< QAngle > m_iv_angRotation;
// Specifies the entity-to-world transform
matrix3x4_t m_rgflCoordinateFrame;
// used to cull collision tests
int m_CollisionGroup;
#if !defined( NO_ENTITY_PREDICTION )
// For storing prediction results and pristine network state
byte *m_pIntermediateData[ MULTIPLAYER_BACKUP ]; byte *m_pIntermediateData_FirstPredicted[ MULTIPLAYER_BACKUP + 1 ]; //we store just as much as m_pIntermediateData, but also hold onto the frame from our last received packet
byte *m_pOriginalData; int m_nIntermediateDataCount; static int s_nIncomingPacketCommandsAcknowledged; //only set to a valid value during entity network update processing
int m_nIntermediateData_FirstPredictedShiftMarker; //can't use predicted commands to optimize first predicted version of ShiftIntermediateDataForward(). Use this instead for its longer lifetime
bool m_bEverHadPredictionErrorsForThisCommand;
bool m_bIsPlayerSimulated; #endif
CNetworkVar( bool, m_bSimulatedEveryTick ); CNetworkVar( bool, m_bAnimatedEveryTick ); CNetworkVar( bool, m_bAlternateSorting ); //CNetworkVar( bool, m_bSpotted );
bool m_bSpotted; bool m_bSpottedBy[MAX_PLAYERS + 1]; // OBSELETE USED BY OLD DEMOS
CNetworkArray( uint32, m_bSpottedByMask, kNumSpottedByMask );
unsigned char m_nMinCPULevel; unsigned char m_nMaxCPULevel; unsigned char m_nMinGPULevel; unsigned char m_nMaxGPULevel;
//Adrian
unsigned char m_iTextureFrameIndex;
// Bbox visualization
unsigned char m_fBBoxVisFlags;
bool m_bIsValidIKAttachment;
// The list that holds OnDataChanged events uses this to make sure we don't get multiple
// OnDataChanged calls in the same frame if the client receives multiple packets.
int m_DataChangeEventRef;
#if !defined( NO_ENTITY_PREDICTION )
// Player who is driving my simulation
CHandle< CBasePlayer > m_hPlayerSimulationOwner; #endif
EHANDLE m_hEffectEntity; // This is a random seed used by the networking code to allow client - side prediction code
// randon number generators to spit out the same random numbers on both sides for a particular
// usercmd input.
static int m_nPredictionRandomSeed; static C_BasePlayer *m_pPredictionPlayer; static bool s_bAbsQueriesValid; static bool s_bAbsRecomputationEnabled;
static bool s_bInterpolate; int m_fDataObjectTypes;
AimEntsListHandle_t m_AimEntsListHandle; int m_nCreationTick;
public: float m_fRenderingClipPlane[4]; //world space clip plane when drawing
bool m_bEnableRenderingClipPlane; //true to use the custom clip plane when drawing
float * GetRenderClipPlane( void ); // Rendering clip plane, should be 4 floats, return value of NULL indicates a disabled render clip plane
bool IsSpotted( void ) { return m_bSpotted && !IsDormant(); } bool IsSpottedBy( int nPlayerIndex ); bool IsSpottedByFriends( int nPlayerIndex );
protected: void SetIsSpottedBy( int nPlayerEntIndex );
void AddToEntityList( entity_list_ids_t listId ); void RemoveFromEntityList( entity_list_ids_t listId ); unsigned short m_ListEntry[NUM_ENTITY_LISTS]; // Entry into each g_EntityList (or InvalidIndex() if not in the list).
CThreadFastMutex m_CalcAbsolutePositionMutex; CThreadFastMutex m_CalcAbsoluteVelocityMutex;
private: bool m_bIsBlurred; };
EXTERN_RECV_TABLE(DT_BaseEntity);
inline bool FClassnameIs( C_BaseEntity *pEntity, const char *szClassname ) { Assert( pEntity ); return pEntity && !strcmp( pEntity->GetClassname(), szClassname ); }
#define SetThink( a ) ThinkSet( static_cast <void (CBaseEntity::*)(void)> (a), 0, NULL )
#define SetContextThink( a, b, context ) ThinkSet( static_cast <void (CBaseEntity::*)(void)> (a), (b), context )
#ifdef _DEBUG
#define SetTouch( a ) TouchSet( static_cast <void (C_BaseEntity::*)(C_BaseEntity *)> (a), #a )
#else
#define SetTouch( a ) m_pfnTouch = static_cast <void (C_BaseEntity::*)(C_BaseEntity *)> (a)
#endif
//-----------------------------------------------------------------------------
// An inline version the game code can use
//-----------------------------------------------------------------------------
inline CCollisionProperty *C_BaseEntity::CollisionProp() { return m_Collision.Get(); }
inline const CCollisionProperty *C_BaseEntity::CollisionProp() const { return m_Collision.Get(); }
inline CClientAlphaProperty *C_BaseEntity::AlphaProp() { return m_pClientAlphaProperty; }
inline const CClientAlphaProperty *C_BaseEntity::AlphaProp() const { return m_pClientAlphaProperty; }
//-----------------------------------------------------------------------------
// An inline version the game code can use
//-----------------------------------------------------------------------------
inline CParticleProperty *C_BaseEntity::ParticleProp() { return m_Particles.Get(); }
inline const CParticleProperty *C_BaseEntity::ParticleProp() const { return m_Particles.Get(); }
//-----------------------------------------------------------------------------
// Purpose: Returns whether this entity was created on the client.
//-----------------------------------------------------------------------------
inline bool C_BaseEntity::IsServerEntity( void ) const { return index != -1; }
//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
inline matrix3x4_t &C_BaseEntity::EntityToWorldTransform() { Assert( s_bAbsQueriesValid ); CalcAbsolutePosition(); return m_rgflCoordinateFrame; }
inline const matrix3x4_t &C_BaseEntity::EntityToWorldTransform() const { Assert( s_bAbsQueriesValid ); const_cast<C_BaseEntity*>(this)->CalcAbsolutePosition(); return m_rgflCoordinateFrame; }
//-----------------------------------------------------------------------------
// Some helper methods that transform a point from entity space to world space + back
//-----------------------------------------------------------------------------
inline void C_BaseEntity::EntityToWorldSpace( const Vector &in, Vector *pOut ) const { if ( GetAbsAngles() == vec3_angle ) { VectorAdd( in, GetAbsOrigin(), *pOut ); } else { VectorTransform( in, EntityToWorldTransform(), *pOut ); } }
inline void C_BaseEntity::WorldToEntitySpace( const Vector &in, Vector *pOut ) const { if ( GetAbsAngles() == vec3_angle ) { VectorSubtract( in, GetAbsOrigin(), *pOut ); } else { VectorITransform( in, EntityToWorldTransform(), *pOut ); } }
inline const Vector &C_BaseEntity::GetAbsVelocity( ) const { Assert( s_bAbsQueriesValid ); const_cast<C_BaseEntity*>(this)->CalcAbsoluteVelocity(); return m_vecAbsVelocity; }
inline C_BaseEntity *C_BaseEntity::Instance( IClientEntity *ent ) { return ent ? ent->GetBaseEntity() : NULL; }
// For debugging shared code
inline bool C_BaseEntity::IsServer( void ) { return false; }
inline bool C_BaseEntity::IsClient( void ) { return true; }
inline const char *C_BaseEntity::GetDLLType( void ) { return "client"; }
//-----------------------------------------------------------------------------
// Methods relating to solid type + flags
//-----------------------------------------------------------------------------
inline void C_BaseEntity::SetSolidFlags( int nFlags ) { CollisionProp()->SetSolidFlags( nFlags ); }
inline bool C_BaseEntity::IsSolidFlagSet( int flagMask ) const { return CollisionProp()->IsSolidFlagSet( flagMask ); }
inline int C_BaseEntity::GetSolidFlags( void ) const { return CollisionProp()->GetSolidFlags( ); }
inline void C_BaseEntity::AddSolidFlags( int nFlags ) { CollisionProp()->AddSolidFlags( nFlags ); }
inline void C_BaseEntity::RemoveSolidFlags( int nFlags ) { CollisionProp()->RemoveSolidFlags( nFlags ); }
inline bool C_BaseEntity::IsSolid() const { return CollisionProp()->IsSolid( ); }
inline void C_BaseEntity::SetSolid( SolidType_t val ) { CollisionProp()->SetSolid( val ); }
inline SolidType_t C_BaseEntity::GetSolid( ) const { return CollisionProp()->GetSolid( ); }
inline void C_BaseEntity::SetCollisionBounds( const Vector& mins, const Vector &maxs ) { CollisionProp()->SetCollisionBounds( mins, maxs ); }
//-----------------------------------------------------------------------------
// Methods relating to bounds
//-----------------------------------------------------------------------------
inline const Vector& C_BaseEntity::WorldAlignMins( ) const { Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); return CollisionProp()->OBBMins(); }
inline const Vector& C_BaseEntity::WorldAlignMaxs( ) const { Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); return CollisionProp()->OBBMaxs(); }
inline const Vector& C_BaseEntity::WorldAlignSize( ) const { Assert( !CollisionProp()->IsBoundsDefinedInEntitySpace() ); Assert( CollisionProp()->GetCollisionAngles() == vec3_angle ); return CollisionProp()->OBBSize(); }
inline float CBaseEntity::BoundingRadius() const { return CollisionProp()->BoundingRadius(); }
inline bool CBaseEntity::IsPointSized() const { return CollisionProp()->BoundingRadius() == 0.0f; }
//-----------------------------------------------------------------------------
// Methods relating to traversing hierarchy
//-----------------------------------------------------------------------------
inline C_BaseEntity *C_BaseEntity::GetMoveParent( void ) const { return m_pMoveParent; }
inline C_BaseEntity *C_BaseEntity::FirstMoveChild( void ) const { return m_pMoveChild; }
inline C_BaseEntity *C_BaseEntity::NextMovePeer( void ) const { return m_pMovePeer; }
//-----------------------------------------------------------------------------
// Velocity
//-----------------------------------------------------------------------------
inline const Vector& C_BaseEntity::GetLocalVelocity() const { return m_vecVelocity; }
inline const QAngle& C_BaseEntity::GetLocalAngularVelocity( ) const { return m_vecAngVelocity; }
inline const Vector& C_BaseEntity::GetBaseVelocity() const { return m_vecBaseVelocity; }
inline void C_BaseEntity::SetBaseVelocity( const Vector& v ) { m_vecBaseVelocity = v; }
inline void C_BaseEntity::SetFriction( float flFriction ) { m_flFriction = flFriction; }
inline void C_BaseEntity::SetGravity( float flGravity ) { m_flGravity = flGravity; }
inline float C_BaseEntity::GetGravity( void ) const { return m_flGravity; }
inline int C_BaseEntity::GetWaterLevel() const { return m_nWaterLevel; }
inline void C_BaseEntity::SetWaterLevel( int nLevel ) { m_nWaterLevel = nLevel; }
inline float C_BaseEntity::GetElasticity( void ) const { return m_flElasticity; }
inline const color24 CBaseEntity::GetRenderColor() const { color24 c = { m_clrRender->r, m_clrRender->g, m_clrRender->b }; return c; }
inline byte C_BaseEntity::GetRenderColorR() const { return m_clrRender->r; }
inline byte C_BaseEntity::GetRenderColorG() const { return m_clrRender->g; }
inline byte C_BaseEntity::GetRenderColorB() const { return m_clrRender->b; }
inline void C_BaseEntity::SetRenderColor( byte r, byte g, byte b ) { m_clrRender.SetR( r ); m_clrRender.SetG( g ); m_clrRender.SetB( b ); }
inline void C_BaseEntity::SetRenderColorR( byte r ) { m_clrRender.SetR( r ); }
inline void C_BaseEntity::SetRenderColorG( byte g ) { m_clrRender.SetG( g ); }
inline void C_BaseEntity::SetRenderColorB( byte b ) { m_clrRender.SetB( b ); }
inline RenderMode_t C_BaseEntity::GetRenderMode() const { return (RenderMode_t)m_nRenderMode; }
inline RenderFx_t C_BaseEntity::GetRenderFX() const { return (RenderFx_t)m_nRenderFX; }
inline void C_BaseEntity::SetCPULevels( int nMinCPULevel, int nMaxCPULevel ) { m_nMinCPULevel = nMinCPULevel; m_nMaxCPULevel = nMaxCPULevel; }
inline void C_BaseEntity::SetGPULevels( int nMinGPULevel, int nMaxGPULevel ) { m_nMinGPULevel = nMinGPULevel; m_nMaxGPULevel = nMaxGPULevel; }
inline int C_BaseEntity::GetMinCPULevel( ) const { return m_nMinCPULevel; }
inline int C_BaseEntity::GetMaxCPULevel( ) const { return m_nMaxCPULevel; }
inline int C_BaseEntity::GetMinGPULevel( ) const { return m_nMinGPULevel; }
inline int C_BaseEntity::GetMaxGPULevel( ) const { return m_nMaxGPULevel; }
//-----------------------------------------------------------------------------
// checks to see if the entity is marked for deletion
//-----------------------------------------------------------------------------
inline bool C_BaseEntity::IsMarkedForDeletion( void ) { return (m_iEFlags & EFL_KILLME); }
inline void C_BaseEntity::AddEFlags( int nEFlagMask ) { m_iEFlags |= nEFlagMask; }
inline void C_BaseEntity::RemoveEFlags( int nEFlagMask ) { m_iEFlags &= ~nEFlagMask; }
inline bool CBaseEntity::IsEFlagSet( int nEFlagMask ) const { return (m_iEFlags & nEFlagMask) != 0; }
inline unsigned char CBaseEntity::GetParentAttachment() const { return m_iParentAttachment; }
inline ClientRenderHandle_t CBaseEntity::GetRenderHandle() const { return m_hRender; }
inline ClientRenderHandle_t& CBaseEntity::RenderHandle() { return m_hRender; }
//-----------------------------------------------------------------------------
// Methods to cast away const
//-----------------------------------------------------------------------------
inline Vector C_BaseEntity::EyePosition( void ) const { return const_cast<C_BaseEntity*>(this)->EyePosition(); }
inline const QAngle &C_BaseEntity::EyeAngles( void ) const // Direction of eyes in world space
{ return const_cast<C_BaseEntity*>(this)->EyeAngles(); }
inline const QAngle &C_BaseEntity::LocalEyeAngles( void ) const // Direction of eyes
{ return const_cast<C_BaseEntity*>(this)->LocalEyeAngles(); }
inline Vector C_BaseEntity::EarPosition( void ) const // position of ears
{ return const_cast<C_BaseEntity*>(this)->EarPosition(); }
inline VarMapping_t* C_BaseEntity::GetVarMapping() { return &m_VarMap; }
//-----------------------------------------------------------------------------
// Should we be interpolating?
//-----------------------------------------------------------------------------
inline bool C_BaseEntity::IsInterpolationEnabled() { return s_bInterpolate; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : handle -
// Output : inline void
//-----------------------------------------------------------------------------
inline void C_BaseEntity::SetToolHandle( HTOOLHANDLE handle ) { #ifndef NO_TOOLFRAMEWORK
m_ToolHandle = handle; #endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : -
// Output : inline HTOOLHANDLE
//-----------------------------------------------------------------------------
inline HTOOLHANDLE C_BaseEntity::GetToolHandle() const { #ifndef NO_TOOLFRAMEWORK
return m_ToolHandle; #else
return (HTOOLHANDLE)0; #endif
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
inline bool C_BaseEntity::IsEnabledInToolView() const { #ifndef NO_TOOLFRAMEWORK
return m_bEnabledInToolView; #else
return false; #endif
}
//-----------------------------------------------------------------------------
// Client version of UTIL_Remove
//-----------------------------------------------------------------------------
inline void UTIL_Remove( C_BaseEntity *pEntity ) { pEntity->Remove(); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : -
// Output : inline bool
//-----------------------------------------------------------------------------
inline bool C_BaseEntity::ShouldRecordInTools() const { #ifndef NO_TOOLFRAMEWORK
return m_bRecordInTools; #else
return true; #endif
}
inline bool C_BaseEntity::IsVisible() const { if ( INVALID_CLIENT_RENDER_HANDLE == m_hRender ) return false; ASSERT_LOCAL_PLAYER_RESOLVABLE(); return m_VisibilityBits.IsBitSet( GET_ACTIVE_SPLITSCREEN_SLOT() ); }
inline bool C_BaseEntity::IsVisibleToAnyPlayer() const { return !m_VisibilityBits.IsAllClear(); }
inline bool C_BaseEntity::HasSpawnFlags( int nFlags ) const { return (m_spawnflags & nFlags) != 0; }
//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
inline const char *C_BaseEntity::GetEntityName() { return m_iName; }
#ifdef PORTAL2
inline const char *C_BaseEntity::GetSignifierName() { return m_iSignifierName; } #endif // PORTAL2
class CAbsQueryScopeGuard { public: explicit CAbsQueryScopeGuard( bool state ) { m_bSavedState = C_BaseEntity::IsAbsQueriesValid(); C_BaseEntity::SetAbsQueriesValid( state ); } ~CAbsQueryScopeGuard() { C_BaseEntity::SetAbsQueriesValid( m_bSavedState ); } private: bool m_bSavedState; };
#define ABS_QUERY_GUARD( state ) CAbsQueryScopeGuard s_AbsQueryGuard( state );
C_BaseEntity *CreateEntityByName( const char *className );
#if !defined( NO_ENTITY_PREDICTION )
class CEntIndexLessFunc { public: bool Less( C_BaseEntity * const & lhs, C_BaseEntity * const & rhs, void *pContext ) { int e1 = lhs->entindex(); int e2 = rhs->entindex();
// if an entity has an invalid entity index, then put it at the end of the list
e1 = ( e1 == -1 ) ? MAX_EDICTS : e1; e2 = ( e2 == -1 ) ? MAX_EDICTS : e2;
return e1 < e2; } };
//-----------------------------------------------------------------------------
// Purpose: Maintains a list of predicted or client created entities
//-----------------------------------------------------------------------------
class CPredictableList { public: C_BaseEntity *GetPredictable( int slot ); int GetPredictableCount( void ) const;
protected: void AddToPredictableList( C_BaseEntity *add ); void RemoveFromPredictablesList( C_BaseEntity *remove );
private: CUtlSortVector< C_BaseEntity *, CEntIndexLessFunc > m_Predictables;
friend class C_BaseEntity; };
//-----------------------------------------------------------------------------
// Purpose:
// Input : slot -
// Output : C_BaseEntity
//-----------------------------------------------------------------------------
FORCEINLINE C_BaseEntity *CPredictableList::GetPredictable( int slot ) { return m_Predictables[ slot ]; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
FORCEINLINE int CPredictableList::GetPredictableCount( void ) const { return m_Predictables.Count(); }
FORCEINLINE int C_BaseEntity::GetSplitUserPlayerPredictionSlot() { #if defined( USE_PREDICTABLEID )
Assert( m_bPredictable || m_pPredictionContext ); #else
Assert( m_bPredictable ); #endif
return m_nSplitUserPlayerPredictionSlot; }
extern CPredictableList *GetPredictables( int nSlot );
// To temporarily muck with gpGlobals->curtime
class CCurTimeScopeGuard { public: CCurTimeScopeGuard( float flNewCurTime, bool bOptionalCondition = true ); ~CCurTimeScopeGuard(); private:
float m_flSavedTime; bool m_bActive; }; #endif
#endif // C_BASEENTITY_H
|