|
|
//========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose: Manages the server moving things back in time to match up to where clients thought they were
// when the client commited an action
//
// $NoKeywords: $
//=============================================================================//
#ifndef _PLAYER_LAG_COMPENSATION_H_
#define _PLAYER_LAG_COMPENSATION_H_
#ifdef _WIN32
#pragma once
#endif
#include "igamesystem.h"
#include "ilagcompensationmanager.h"
#include "utllinkedlist.h"
#define MAX_LAYER_RECORDS (CBaseAnimatingOverlay::MAX_OVERLAYS)
struct LayerRecord { int m_sequence; float m_cycle; float m_weight; int m_order;
LayerRecord() { Clear(); }
LayerRecord( const LayerRecord& src ) { m_sequence = src.m_sequence; m_cycle = src.m_cycle; m_weight = src.m_weight; m_order = src.m_order; }
void Clear() { m_sequence = 0; m_cycle = 0; m_weight = 0; m_order = 0; } };
struct LagRecord { public: LagRecord() { Clear(); }
LagRecord( const LagRecord& src ) { m_fFlags = src.m_fFlags; m_vecOrigin = src.m_vecOrigin; m_vecAngles = src.m_vecAngles; m_vecMins = src.m_vecMins; m_vecMaxs = src.m_vecMaxs; m_flSimulationTime = src.m_flSimulationTime; for( int layerIndex = 0; layerIndex < MAX_LAYER_RECORDS; ++layerIndex ) { m_layerRecords[layerIndex] = src.m_layerRecords[layerIndex]; } m_masterSequence = src.m_masterSequence; m_masterCycle = src.m_masterCycle;
for( int i=0; i<MAXSTUDIOPOSEPARAM; i++ ) { m_flPoseParameters[i] = src.m_flPoseParameters[i]; } }
void Clear() { m_fFlags = 0; m_vecOrigin.Init(); m_vecAngles.Init(); m_vecMins.Init(); m_vecMaxs.Init(); m_flSimulationTime = -1; m_masterSequence = 0; m_masterCycle = 0; for( int layerIndex = 0; layerIndex < MAX_LAYER_RECORDS; ++layerIndex ) { m_layerRecords[layerIndex].Clear(); }
for( int i=0; i<MAXSTUDIOPOSEPARAM; i++ ) { m_flPoseParameters[i] = 0; } }
// Did player die this frame
int m_fFlags;
// Player position, orientation and bbox
Vector m_vecOrigin; QAngle m_vecAngles; Vector m_vecMins; Vector m_vecMaxs;
float m_flSimulationTime;
// Player animation details, so we can get the legs in the right spot.
LayerRecord m_layerRecords[MAX_LAYER_RECORDS]; int m_masterSequence; float m_masterCycle;
float m_flPoseParameters[MAXSTUDIOPOSEPARAM]; };
typedef CUtlFixedLinkedList< LagRecord > LagRecordList;
//-----------------------------------------------------------------------------
class CLagCompensationManager : public CAutoGameSystemPerFrame, public ILagCompensationManager { public: CLagCompensationManager( char const *name ) : CAutoGameSystemPerFrame( name ), m_CompensatedEntities( 0, 0, DefLessFunc( EHANDLE ) ), m_AdditionalEntities( 0, 0, DefLessFunc( EHANDLE ) ) { m_bNeedToRestore = false; m_weaponRange = 0.0f; m_isCurrentlyDoingCompensation = false; }
// IServerSystem stuff
virtual void Shutdown() { ClearHistory(); }
virtual void LevelShutdownPostEntity() { ClearHistory(); }
// called after entities think
virtual void FrameUpdatePostEntityThink();
// ILagCompensationManager stuff
// Called during player movement to set up/restore after lag compensation
void StartLagCompensation( CBasePlayer *player, LagCompensationType lagCompensationType, const Vector& weaponPos = vec3_origin, const QAngle &weaponAngles = vec3_angle, float weaponRange = 0.0f ); void FinishLagCompensation( CBasePlayer *player );
// Mappers can flag certain additional entities to lag compensate, this handles them
virtual void AddAdditionalEntity( CBaseEntity *pEntity ); virtual void RemoveAdditionalEntity( CBaseEntity *pEntity );
void RecordDataIntoTrack( CBaseEntity *entity, LagRecordList *track, bool wantsAnims ); bool BacktrackEntity( CBaseEntity *entity, float flTargetTime, LagRecordList *track, LagRecord *restore, LagRecord *change, bool wantsAnims ); void RestoreEntityFromRecords( CBaseEntity *entity, LagRecord *restore, LagRecord *change, bool wantsAnims ); private:
void ClearHistory() { FOR_EACH_MAP( m_CompensatedEntities, i ) { delete m_CompensatedEntities[ i ]; } m_CompensatedEntities.Purge(); }
struct EntityLagData { EntityLagData() : m_bRestoreEntity( false ) { }
// True if lag compensation altered entity data
bool m_bRestoreEntity; // keep a list of lag records for each player
LagRecordList m_LagRecords;
// Entity data before we moved him back
LagRecord m_RestoreData; // Entity data where we moved him back
LagRecord m_ChangeData; };
CUtlMap< EHANDLE, EntityLagData * > m_CompensatedEntities;
// True if at least one entity was changed
bool m_bNeedToRestore; CBasePlayer *m_pCurrentPlayer; // The player we are doing lag compensation for
LagCompensationType m_lagCompensationType; Vector m_weaponPos; QAngle m_weaponAngles; float m_weaponRange; bool m_isCurrentlyDoingCompensation; // Sentinel to prevent calling StartLagCompensation a second time before a Finish.
// List of additional entities flagged by mappers for lag compensation (shouldn't be more than a few)
CUtlRBTree< EHANDLE > m_AdditionalEntities; };
#endif
|