You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
12 KiB
448 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#ifndef EDICT_H |
|
#define EDICT_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include "mathlib/vector.h" |
|
#include "cmodel.h" |
|
#include "const.h" |
|
#include "iserverentity.h" |
|
#include "globalvars_base.h" |
|
#include "engine/ICollideable.h" |
|
#include "iservernetworkable.h" |
|
#include "bitvec.h" |
|
|
|
struct edict_t; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Defines the ways that a map can be loaded. |
|
//----------------------------------------------------------------------------- |
|
enum MapLoadType_t |
|
{ |
|
MapLoad_NewGame = 0, |
|
MapLoad_LoadGame, |
|
MapLoad_Transition, |
|
MapLoad_Background, |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Global variables shared between the engine and the game .dll |
|
//----------------------------------------------------------------------------- |
|
class CGlobalVars : public CGlobalVarsBase |
|
{ |
|
public: |
|
|
|
CGlobalVars( bool bIsClient ); |
|
|
|
public: |
|
|
|
// Current map |
|
string_t mapname; |
|
int mapversion; |
|
string_t startspot; |
|
MapLoadType_t eLoadType; // How the current map was loaded |
|
bool bMapLoadFailed; // Map has failed to load, we need to kick back to the main menu |
|
|
|
// game specific flags |
|
bool deathmatch; |
|
bool coop; |
|
bool teamplay; |
|
// current maxentities |
|
int maxEntities; |
|
|
|
int serverCount; |
|
}; |
|
|
|
inline CGlobalVars::CGlobalVars( bool bIsClient ) : |
|
CGlobalVarsBase( bIsClient ) |
|
{ |
|
serverCount = 0; |
|
} |
|
|
|
|
|
class CPlayerState; |
|
class IServerNetworkable; |
|
class IServerEntity; |
|
|
|
|
|
#define FL_EDICT_CHANGED (1<<0) // Game DLL sets this when the entity state changes |
|
// Mutually exclusive with FL_EDICT_PARTIAL_CHANGE. |
|
|
|
#define FL_EDICT_FREE (1<<1) // this edict if free for reuse |
|
#define FL_EDICT_FULL (1<<2) // this is a full server entity |
|
|
|
#define FL_EDICT_FULLCHECK (0<<0) // call ShouldTransmit() each time, this is a fake flag |
|
#define FL_EDICT_ALWAYS (1<<3) // always transmit this entity |
|
#define FL_EDICT_DONTSEND (1<<4) // don't transmit this entity |
|
#define FL_EDICT_PVSCHECK (1<<5) // always transmit entity, but cull against PVS |
|
|
|
// Used by local network backdoor. |
|
#define FL_EDICT_PENDING_DORMANT_CHECK (1<<6) |
|
|
|
// This is always set at the same time EFL_DIRTY_PVS_INFORMATION is set, but it |
|
// gets cleared in a different place. |
|
#define FL_EDICT_DIRTY_PVS_INFORMATION (1<<7) |
|
|
|
// This is used internally to edict_t to remember that it's carrying a |
|
// "full change list" - all its properties might have changed their value. |
|
#define FL_FULL_EDICT_CHANGED (1<<8) |
|
|
|
|
|
// Max # of variable changes we'll track in an entity before we treat it |
|
// like they all changed. |
|
#define MAX_CHANGE_OFFSETS 19 |
|
#define MAX_EDICT_CHANGE_INFOS 100 |
|
|
|
|
|
class CEdictChangeInfo |
|
{ |
|
public: |
|
// Edicts remember the offsets of properties that change |
|
unsigned short m_ChangeOffsets[MAX_CHANGE_OFFSETS]; |
|
unsigned short m_nChangeOffsets; |
|
}; |
|
|
|
// Shared between engine and game DLL. |
|
class CSharedEdictChangeInfo |
|
{ |
|
public: |
|
CSharedEdictChangeInfo() |
|
{ |
|
m_iSerialNumber = 1; |
|
} |
|
|
|
// Matched against edict_t::m_iChangeInfoSerialNumber to determine if its |
|
// change info is valid. |
|
unsigned short m_iSerialNumber; |
|
|
|
CEdictChangeInfo m_ChangeInfos[MAX_EDICT_CHANGE_INFOS]; |
|
unsigned short m_nChangeInfos; // How many are in use this frame. |
|
}; |
|
extern CSharedEdictChangeInfo *g_pSharedChangeInfo; |
|
|
|
class IChangeInfoAccessor |
|
{ |
|
public: |
|
inline void SetChangeInfo( unsigned short info ) |
|
{ |
|
m_iChangeInfo = info; |
|
} |
|
|
|
inline void SetChangeInfoSerialNumber( unsigned short sn ) |
|
{ |
|
m_iChangeInfoSerialNumber = sn; |
|
} |
|
|
|
inline unsigned short GetChangeInfo() const |
|
{ |
|
return m_iChangeInfo; |
|
} |
|
|
|
inline unsigned short GetChangeInfoSerialNumber() const |
|
{ |
|
return m_iChangeInfoSerialNumber; |
|
} |
|
|
|
private: |
|
unsigned short m_iChangeInfo; |
|
unsigned short m_iChangeInfoSerialNumber; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
// NOTE: YOU CAN'T CHANGE THE LAYOUT OR SIZE OF CBASEEDICT AND REMAIN COMPATIBLE WITH HL2_VC6!!!!! |
|
class CBaseEdict |
|
{ |
|
public: |
|
|
|
// Returns an IServerEntity if FL_FULLEDICT is set or NULL if this |
|
// is a lightweight networking entity. |
|
IServerEntity* GetIServerEntity(); |
|
const IServerEntity* GetIServerEntity() const; |
|
|
|
IServerNetworkable* GetNetworkable(); |
|
IServerUnknown* GetUnknown(); |
|
|
|
// Set when initting an entity. If it's only a networkable, this is false. |
|
void SetEdict( IServerUnknown *pUnk, bool bFullEdict ); |
|
|
|
int AreaNum() const; |
|
const char * GetClassName() const; |
|
|
|
bool IsFree() const; |
|
void SetFree(); |
|
void ClearFree(); |
|
|
|
bool HasStateChanged() const; |
|
void ClearStateChanged(); |
|
void StateChanged(); |
|
void StateChanged( unsigned short offset ); |
|
|
|
void ClearTransmitState(); |
|
|
|
void SetChangeInfo( unsigned short info ); |
|
void SetChangeInfoSerialNumber( unsigned short sn ); |
|
unsigned short GetChangeInfo() const; |
|
unsigned short GetChangeInfoSerialNumber() const; |
|
|
|
public: |
|
|
|
// NOTE: this is in the edict instead of being accessed by a virtual because the engine needs fast access to it. |
|
// NOTE: YOU CAN'T CHANGE THE LAYOUT OR SIZE OF CBASEEDICT AND REMAIN COMPATIBLE WITH HL2_VC6!!!!! |
|
#ifdef _XBOX |
|
unsigned short m_fStateFlags; |
|
#else |
|
int m_fStateFlags; |
|
#endif |
|
|
|
// NOTE: this is in the edict instead of being accessed by a virtual because the engine needs fast access to it. |
|
// int m_NetworkSerialNumber; |
|
|
|
// NOTE: m_EdictIndex is an optimization since computing the edict index |
|
// from a CBaseEdict* pointer otherwise requires divide-by-20. values for |
|
// m_NetworkSerialNumber all fit within a 16-bit integer range, so we're |
|
// repurposing the other 16 bits to cache off the index without changing |
|
// the overall layout or size of this struct. existing mods compiled with |
|
// a full 32-bit serial number field should still work. henryg 8/17/2011 |
|
#if VALVE_LITTLE_ENDIAN |
|
short m_NetworkSerialNumber; |
|
short m_EdictIndex; |
|
#else |
|
short m_EdictIndex; |
|
short m_NetworkSerialNumber; |
|
#endif |
|
|
|
// NOTE: this is in the edict instead of being accessed by a virtual because the engine needs fast access to it. |
|
IServerNetworkable *m_pNetworkable; |
|
|
|
protected: |
|
IServerUnknown *m_pUnk; |
|
|
|
|
|
public: |
|
|
|
IChangeInfoAccessor *GetChangeAccessor(); // The engine implements this and the game .dll implements as |
|
const IChangeInfoAccessor *GetChangeAccessor() const; // The engine implements this and the game .dll implements as |
|
// as callback through to the engine!!! |
|
|
|
// NOTE: YOU CAN'T CHANGE THE LAYOUT OR SIZE OF CBASEEDICT AND REMAIN COMPATIBLE WITH HL2_VC6!!!!! |
|
// This breaks HL2_VC6!!!!! |
|
// References a CEdictChangeInfo with a list of modified network props. |
|
//unsigned short m_iChangeInfo; |
|
//unsigned short m_iChangeInfoSerialNumber; |
|
|
|
friend void InitializeEntityDLLFields( edict_t *pEdict ); |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CBaseEdict inlines. |
|
//----------------------------------------------------------------------------- |
|
inline IServerEntity* CBaseEdict::GetIServerEntity() |
|
{ |
|
if ( m_fStateFlags & FL_EDICT_FULL ) |
|
return (IServerEntity*)m_pUnk; |
|
else |
|
return 0; |
|
} |
|
|
|
inline bool CBaseEdict::IsFree() const |
|
{ |
|
return (m_fStateFlags & FL_EDICT_FREE) != 0; |
|
} |
|
|
|
|
|
|
|
inline bool CBaseEdict::HasStateChanged() const |
|
{ |
|
return (m_fStateFlags & FL_EDICT_CHANGED) != 0; |
|
} |
|
|
|
inline void CBaseEdict::ClearStateChanged() |
|
{ |
|
m_fStateFlags &= ~(FL_EDICT_CHANGED | FL_FULL_EDICT_CHANGED); |
|
SetChangeInfoSerialNumber( 0 ); |
|
} |
|
|
|
inline void CBaseEdict::StateChanged() |
|
{ |
|
// Note: this should only happen for properties in data tables that used some |
|
// kind of pointer dereference. If the data is directly offsetable |
|
m_fStateFlags |= (FL_EDICT_CHANGED | FL_FULL_EDICT_CHANGED); |
|
SetChangeInfoSerialNumber( 0 ); |
|
} |
|
|
|
inline void CBaseEdict::StateChanged( unsigned short offset ) |
|
{ |
|
if ( m_fStateFlags & FL_FULL_EDICT_CHANGED ) |
|
return; |
|
|
|
m_fStateFlags |= FL_EDICT_CHANGED; |
|
|
|
IChangeInfoAccessor *accessor = GetChangeAccessor(); |
|
|
|
if ( accessor->GetChangeInfoSerialNumber() == g_pSharedChangeInfo->m_iSerialNumber ) |
|
{ |
|
// Ok, I still own this one. |
|
CEdictChangeInfo *p = &g_pSharedChangeInfo->m_ChangeInfos[accessor->GetChangeInfo()]; |
|
|
|
// Now add this offset to our list of changed variables. |
|
for ( unsigned short i=0; i < p->m_nChangeOffsets; i++ ) |
|
if ( p->m_ChangeOffsets[i] == offset ) |
|
return; |
|
|
|
if ( p->m_nChangeOffsets == MAX_CHANGE_OFFSETS ) |
|
{ |
|
// Invalidate our change info. |
|
accessor->SetChangeInfoSerialNumber( 0 ); |
|
m_fStateFlags |= FL_FULL_EDICT_CHANGED; // So we don't get in here again. |
|
} |
|
else |
|
{ |
|
p->m_ChangeOffsets[p->m_nChangeOffsets++] = offset; |
|
} |
|
} |
|
else |
|
{ |
|
if ( g_pSharedChangeInfo->m_nChangeInfos == MAX_EDICT_CHANGE_INFOS ) |
|
{ |
|
// Shucks.. have to mark the edict as fully changed because we don't have room to remember this change. |
|
accessor->SetChangeInfoSerialNumber( 0 ); |
|
m_fStateFlags |= FL_FULL_EDICT_CHANGED; |
|
} |
|
else |
|
{ |
|
// Get a new CEdictChangeInfo and fill it out. |
|
accessor->SetChangeInfo( g_pSharedChangeInfo->m_nChangeInfos ); |
|
g_pSharedChangeInfo->m_nChangeInfos++; |
|
|
|
accessor->SetChangeInfoSerialNumber( g_pSharedChangeInfo->m_iSerialNumber ); |
|
|
|
CEdictChangeInfo *p = &g_pSharedChangeInfo->m_ChangeInfos[accessor->GetChangeInfo()]; |
|
p->m_ChangeOffsets[0] = offset; |
|
p->m_nChangeOffsets = 1; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
inline void CBaseEdict::SetFree() |
|
{ |
|
m_fStateFlags |= FL_EDICT_FREE; |
|
} |
|
|
|
// WARNING: Make sure you don't really want to call ED_ClearFreeFlag which will also |
|
// remove this edict from the g_FreeEdicts bitset. |
|
inline void CBaseEdict::ClearFree() |
|
{ |
|
m_fStateFlags &= ~FL_EDICT_FREE; |
|
} |
|
|
|
inline void CBaseEdict::ClearTransmitState() |
|
{ |
|
m_fStateFlags &= ~(FL_EDICT_ALWAYS|FL_EDICT_PVSCHECK|FL_EDICT_DONTSEND); |
|
} |
|
|
|
inline const IServerEntity* CBaseEdict::GetIServerEntity() const |
|
{ |
|
if ( m_fStateFlags & FL_EDICT_FULL ) |
|
return (IServerEntity*)m_pUnk; |
|
else |
|
return 0; |
|
} |
|
|
|
inline IServerUnknown* CBaseEdict::GetUnknown() |
|
{ |
|
return m_pUnk; |
|
} |
|
|
|
inline IServerNetworkable* CBaseEdict::GetNetworkable() |
|
{ |
|
return m_pNetworkable; |
|
} |
|
|
|
inline void CBaseEdict::SetEdict( IServerUnknown *pUnk, bool bFullEdict ) |
|
{ |
|
m_pUnk = pUnk; |
|
if ( (pUnk != NULL) && bFullEdict ) |
|
{ |
|
m_fStateFlags = FL_EDICT_FULL; |
|
} |
|
else |
|
{ |
|
m_fStateFlags = 0; |
|
} |
|
} |
|
|
|
inline int CBaseEdict::AreaNum() const |
|
{ |
|
if ( !m_pUnk ) |
|
return 0; |
|
|
|
return m_pNetworkable->AreaNum(); |
|
} |
|
|
|
inline const char * CBaseEdict::GetClassName() const |
|
{ |
|
if ( !m_pUnk ) |
|
return ""; |
|
return m_pNetworkable->GetClassName(); |
|
} |
|
|
|
inline void CBaseEdict::SetChangeInfo( unsigned short info ) |
|
{ |
|
GetChangeAccessor()->SetChangeInfo( info ); |
|
} |
|
|
|
inline void CBaseEdict::SetChangeInfoSerialNumber( unsigned short sn ) |
|
{ |
|
GetChangeAccessor()->SetChangeInfoSerialNumber( sn ); |
|
} |
|
|
|
inline unsigned short CBaseEdict::GetChangeInfo() const |
|
{ |
|
return GetChangeAccessor()->GetChangeInfo(); |
|
} |
|
|
|
inline unsigned short CBaseEdict::GetChangeInfoSerialNumber() const |
|
{ |
|
return GetChangeAccessor()->GetChangeInfoSerialNumber(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: The engine's internal representation of an entity, including some |
|
// basic collision and position info and a pointer to the class wrapped on top |
|
// of the structure |
|
//----------------------------------------------------------------------------- |
|
struct edict_t : public CBaseEdict |
|
{ |
|
public: |
|
ICollideable *GetCollideable(); |
|
|
|
// The server timestampe at which the edict was freed (so we can try to use other edicts before reallocating this one) |
|
float freetime; |
|
}; |
|
|
|
inline ICollideable *edict_t::GetCollideable() |
|
{ |
|
IServerEntity *pEnt = GetIServerEntity(); |
|
if ( pEnt ) |
|
return pEnt->GetCollideable(); |
|
else |
|
return NULL; |
|
} |
|
|
|
|
|
#endif // EDICT_H
|
|
|