1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
|
//========= 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
|