Quake II RTX doxygen  1.0 dev
entities.c File Reference
#include "server.h"

Go to the source code of this file.

Macros

#define Q2PRO_OPTIMIZE(c)   ((c)->protocol == PROTOCOL_VERSION_Q2PRO && !(c)->settings[CLS_RECORDING])
 

Functions

static void SV_EmitPacketEntities (client_t *client, client_frame_t *from, client_frame_t *to, int clientEntityNum)
 
static client_frame_tget_last_frame (client_t *client)
 
void SV_WriteFrameToClient_Default (client_t *client)
 
void SV_WriteFrameToClient_Enhanced (client_t *client)
 
void SV_BuildClientFrame (client_t *client)
 

Macro Definition Documentation

◆ Q2PRO_OPTIMIZE

#define Q2PRO_OPTIMIZE (   c)    ((c)->protocol == PROTOCOL_VERSION_Q2PRO && !(c)->settings[CLS_RECORDING])

Definition at line 31 of file entities.c.

Function Documentation

◆ get_last_frame()

static client_frame_t* get_last_frame ( client_t client)
static

Definition at line 134 of file entities.c.

135 {
136  client_frame_t *frame;
137 
138  if (client->lastframe <= 0) {
139  // client is asking for a retransmit
140  client->frames_nodelta++;
141  return NULL;
142  }
143 
144  client->frames_nodelta = 0;
145 
146  if (client->framenum - client->lastframe >= UPDATE_BACKUP) {
147  // client hasn't gotten a good message through in a long time
148  Com_DPrintf("%s: delta request from out-of-date packet.\n", client->name);
149  return NULL;
150  }
151 
152  // we have a valid message to delta from
153  frame = &client->frames[client->lastframe & UPDATE_MASK];
154  if (frame->number != client->lastframe) {
155  // but it got never sent
156  Com_DPrintf("%s: delta request from dropped frame.\n", client->name);
157  return NULL;
158  }
159 
160  if (svs.next_entity - frame->first_entity > svs.num_entities) {
161  // but entities are too old
162  Com_DPrintf("%s: delta request from out-of-date entities.\n", client->name);
163  return NULL;
164  }
165 
166  return frame;
167 }

Referenced by SV_WriteFrameToClient_Default(), and SV_WriteFrameToClient_Enhanced().

◆ SV_BuildClientFrame()

void SV_BuildClientFrame ( client_t client)

Definition at line 382 of file entities.c.

383 {
384  int e;
385  vec3_t org;
386  edict_t *ent;
387  edict_t *clent;
388  client_frame_t *frame;
389  entity_packed_t *state;
390  player_state_t *ps;
391  entity_state_t es;
392  int l;
393  int clientarea, clientcluster;
394  mleaf_t *leaf;
395  byte clientphs[VIS_MAX_BYTES];
396  byte clientpvs[VIS_MAX_BYTES];
397  qboolean ent_visible;
398  int cull_nonvisible_entities = Cvar_Get("sv_cull_nonvisible_entities", "1", CVAR_CHEAT)->integer;
399 
400  clent = client->edict;
401  if (!clent->client)
402  return; // not in game yet
403 
404  // this is the frame we are creating
405  frame = &client->frames[client->framenum & UPDATE_MASK];
406  frame->number = client->framenum;
407  frame->sentTime = com_eventTime; // save it for ping calc later
408  frame->latency = -1; // not yet acked
409 
410  client->frames_sent++;
411 
412  // find the client's PVS
413  ps = &clent->client->ps;
414  VectorMA(ps->viewoffset, 0.125f, ps->pmove.origin, org);
415 
416  leaf = CM_PointLeaf(client->cm, org);
417  clientarea = CM_LeafArea(leaf);
418  clientcluster = CM_LeafCluster(leaf);
419 
420  // calculate the visible areas
421  frame->areabytes = CM_WriteAreaBits(client->cm, frame->areabits, clientarea);
422  if (!frame->areabytes && client->protocol != PROTOCOL_VERSION_Q2PRO) {
423  frame->areabits[0] = 255;
424  frame->areabytes = 1;
425  }
426 
427  // grab the current player_state_t
428  MSG_PackPlayer(&frame->ps, ps);
429 
430  // grab the current clientNum
431  if (g_features->integer & GMF_CLIENTNUM) {
432  frame->clientNum = clent->client->clientNum;
433  } else {
434  frame->clientNum = client->number;
435  }
436 
437  if (clientcluster >= 0)
438  {
439  CM_FatPVS(client->cm, clientpvs, org, DVIS_PVS2);
440  client->last_valid_cluster = clientcluster;
441  }
442  else
443  {
444  BSP_ClusterVis(client->cm->cache, clientpvs, client->last_valid_cluster, DVIS_PVS2);
445  }
446 
447  BSP_ClusterVis(client->cm->cache, clientphs, clientcluster, DVIS_PHS);
448 
449  // build up the list of visible entities
450  frame->num_entities = 0;
451  frame->first_entity = svs.next_entity;
452 
453  for (e = 1; e < client->pool->num_edicts; e++) {
454  ent = EDICT_POOL(client, e);
455 
456  // ignore entities not in use
457  if (!ent->inuse && (g_features->integer & GMF_PROPERINUSE)) {
458  continue;
459  }
460 
461  // ignore ents without visible models
462  if (ent->svflags & SVF_NOCLIENT)
463  continue;
464 
465  // ignore ents without visible models unless they have an effect
466  if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound) {
467  if (!ent->s.event) {
468  continue;
469  }
470  if (ent->s.event == EV_FOOTSTEP && client->settings[CLS_NOFOOTSTEPS]) {
471  continue;
472  }
473  }
474 
475  if ((ent->s.effects & EF_GIB) && client->settings[CLS_NOGIBS]) {
476  continue;
477  }
478 
479  ent_visible = qtrue;
480 
481  // ignore if not touching a PV leaf
482  if (ent != clent) {
483  // check area
484  if (clientcluster >= 0 && !CM_AreasConnected(client->cm, clientarea, ent->areanum)) {
485  // doors can legally straddle two areas, so
486  // we may need to check another one
487  if (!CM_AreasConnected(client->cm, clientarea, ent->areanum2)) {
488  ent_visible = qfalse; // blocked by a door
489  }
490  }
491 
492  if (ent_visible)
493  {
494  // beams just check one point for PHS
495  if (ent->s.renderfx & RF_BEAM) {
496  l = ent->clusternums[0];
497  if (!Q_IsBitSet(clientphs, l))
498  ent_visible = qfalse;
499  }
500  else {
501  if (cull_nonvisible_entities && !SV_EdictIsVisible(client->cm, ent, clientpvs)) {
502  ent_visible = qfalse;
503  }
504 
505  if (!ent->s.modelindex) {
506  // don't send sounds if they will be attenuated away
507  vec3_t delta;
508  float len;
509 
510  VectorSubtract(org, ent->s.origin, delta);
511  len = VectorLength(delta);
512  if (len > 400)
513  ent_visible = qfalse;
514  }
515  }
516  }
517  }
518 
519  if(!ent_visible && (!sv_novis->integer || !ent->s.modelindex))
520  continue;
521 
522  if (ent->s.number != e) {
523  Com_WPrintf("%s: fixing ent->s.number: %d to %d\n",
524  __func__, ent->s.number, e);
525  ent->s.number = e;
526  }
527 
528  memcpy(&es, &ent->s, sizeof(entity_state_t));
529 
530  if (!ent_visible) {
531  // if the entity is invisible, kill its sound
532  es.sound = 0;
533  }
534 
535  // add it to the circular client_entities array
537  MSG_PackEntity(state, &es, Q2PRO_SHORTANGLES(client, e));
538 
539 #if USE_FPS
540  // fix old entity origins for clients not running at
541  // full server frame rate
542  if (client->framediv != 1)
543  fix_old_origin(client, state, ent, e);
544 #endif
545 
546  // clear footsteps
547  if (state->event == EV_FOOTSTEP && client->settings[CLS_NOFOOTSTEPS]) {
548  state->event = 0;
549  }
550 
551  // hide POV entity from renderer, unless this is player's own entity
552  if (e == frame->clientNum + 1 && ent != clent &&
553  (g_features->integer & GMF_CLIENTNUM) && !Q2PRO_OPTIMIZE(client)) {
554  state->modelindex = 0;
555  }
556 
557 #if USE_MVD_CLIENT
558  if (sv.state == ss_broadcast) {
559  // spectators only need to know about inline BSP models
560  if (state->solid != PACKED_BSP)
561  state->solid = 0;
562  } else
563 #endif
564  if (ent->owner == clent) {
565  // don't mark players missiles as solid
566  state->solid = 0;
567  } else if (client->esFlags & MSG_ES_LONGSOLID) {
568  state->solid = sv.entities[e].solid32;
569  }
570 
571  svs.next_entity++;
572 
573  if (++frame->num_entities == MAX_PACKET_ENTITIES) {
574  break;
575  }
576  }
577 }

Referenced by SV_SendClientMessages().

◆ SV_EmitPacketEntities()

static void SV_EmitPacketEntities ( client_t client,
client_frame_t from,
client_frame_t to,
int  clientEntityNum 
)
static

Definition at line 41 of file entities.c.

45 {
46  entity_packed_t *newent;
47  const entity_packed_t *oldent;
48  unsigned i, oldindex, newindex, from_num_entities;
49  int oldnum, newnum;
50  msgEsFlags_t flags;
51 
52  if (!from)
53  from_num_entities = 0;
54  else
55  from_num_entities = from->num_entities;
56 
57  newindex = 0;
58  oldindex = 0;
59  oldent = newent = NULL;
60  while (newindex < to->num_entities || oldindex < from_num_entities) {
61  if (newindex >= to->num_entities) {
62  newnum = 9999;
63  } else {
64  i = (to->first_entity + newindex) % svs.num_entities;
65  newent = &svs.entities[i];
66  newnum = newent->number;
67  }
68 
69  if (oldindex >= from_num_entities) {
70  oldnum = 9999;
71  } else {
72  i = (from->first_entity + oldindex) % svs.num_entities;
73  oldent = &svs.entities[i];
74  oldnum = oldent->number;
75  }
76 
77  if (newnum == oldnum) {
78  // Delta update from old position. Because the force parm is false,
79  // this will not result in any bytes being emitted if the entity has
80  // not changed at all. Note that players are always 'newentities',
81  // this updates their old_origin always and prevents warping in case
82  // of packet loss.
83  flags = client->esFlags;
84  if (newnum <= client->maxclients) {
85  flags |= MSG_ES_NEWENTITY;
86  }
87  if (newnum == clientEntityNum) {
88  flags |= MSG_ES_FIRSTPERSON;
89  VectorCopy(oldent->origin, newent->origin);
90  VectorCopy(oldent->angles, newent->angles);
91  }
92  if (Q2PRO_SHORTANGLES(client, newnum)) {
93  flags |= MSG_ES_SHORTANGLES;
94  }
95  MSG_WriteDeltaEntity(oldent, newent, flags);
96  oldindex++;
97  newindex++;
98  continue;
99  }
100 
101  if (newnum < oldnum) {
102  // this is a new entity, send it from the baseline
103  flags = client->esFlags | MSG_ES_FORCE | MSG_ES_NEWENTITY;
104  oldent = client->baselines[newnum >> SV_BASELINES_SHIFT];
105  if (oldent) {
106  oldent += (newnum & SV_BASELINES_MASK);
107  } else {
108  oldent = &nullEntityState;
109  }
110  if (newnum == clientEntityNum) {
111  flags |= MSG_ES_FIRSTPERSON;
112  VectorCopy(oldent->origin, newent->origin);
113  VectorCopy(oldent->angles, newent->angles);
114  }
115  if (Q2PRO_SHORTANGLES(client, newnum)) {
116  flags |= MSG_ES_SHORTANGLES;
117  }
118  MSG_WriteDeltaEntity(oldent, newent, flags);
119  newindex++;
120  continue;
121  }
122 
123  if (newnum > oldnum) {
124  // the old entity isn't present in the new message
125  MSG_WriteDeltaEntity(oldent, NULL, MSG_ES_FORCE);
126  oldindex++;
127  continue;
128  }
129  }
130 
131  MSG_WriteShort(0); // end of packetentities
132 }

Referenced by SV_WriteFrameToClient_Default(), and SV_WriteFrameToClient_Enhanced().

◆ SV_WriteFrameToClient_Default()

void SV_WriteFrameToClient_Default ( client_t client)

Definition at line 174 of file entities.c.

175 {
176  client_frame_t *frame, *oldframe;
177  player_packed_t *oldstate;
178  int lastframe;
179 
180  // this is the frame we are creating
181  frame = &client->frames[client->framenum & UPDATE_MASK];
182 
183  // this is the frame we are delta'ing from
184  oldframe = get_last_frame(client);
185  if (oldframe) {
186  oldstate = &oldframe->ps;
187  lastframe = client->lastframe;
188  } else {
189  oldstate = NULL;
190  lastframe = -1;
191  }
192 
193  MSG_WriteByte(svc_frame);
194  MSG_WriteLong(client->framenum);
195  MSG_WriteLong(lastframe); // what we are delta'ing from
196  MSG_WriteByte(client->suppress_count); // rate dropped packets
197  client->suppress_count = 0;
198  client->frameflags = 0;
199 
200  // send over the areabits
201  MSG_WriteByte(frame->areabytes);
202  MSG_WriteData(frame->areabits, frame->areabytes);
203 
204  // delta encode the playerstate
205  MSG_WriteByte(svc_playerinfo);
206  MSG_WriteDeltaPlayerstate_Default(oldstate, &frame->ps);
207 
208  // delta encode the entities
209  MSG_WriteByte(svc_packetentities);
210  SV_EmitPacketEntities(client, oldframe, frame, 0);
211 }

Referenced by SVC_DirectConnect().

◆ SV_WriteFrameToClient_Enhanced()

void SV_WriteFrameToClient_Enhanced ( client_t client)

Definition at line 218 of file entities.c.

219 {
220  client_frame_t *frame, *oldframe;
221  player_packed_t *oldstate;
222  uint32_t extraflags;
223  int delta, suppressed;
224  byte *b1, *b2;
225  msgPsFlags_t psFlags;
226  int clientEntityNum;
227 
228  // this is the frame we are creating
229  frame = &client->frames[client->framenum & UPDATE_MASK];
230 
231  // this is the frame we are delta'ing from
232  oldframe = get_last_frame(client);
233  if (oldframe) {
234  oldstate = &oldframe->ps;
235  delta = client->framenum - client->lastframe;
236  } else {
237  oldstate = NULL;
238  delta = 31;
239  }
240 
241  // first byte to be patched
242  b1 = SZ_GetSpace(&msg_write, 1);
243 
244  MSG_WriteLong((client->framenum & FRAMENUM_MASK) | (delta << FRAMENUM_BITS));
245 
246  // second byte to be patched
247  b2 = SZ_GetSpace(&msg_write, 1);
248 
249  // send over the areabits
250  MSG_WriteByte(frame->areabytes);
251  MSG_WriteData(frame->areabits, frame->areabytes);
252 
253  // ignore some parts of playerstate if not recording demo
254  psFlags = 0;
255  if (!client->settings[CLS_RECORDING]) {
256  if (client->settings[CLS_NOGUN]) {
257  psFlags |= MSG_PS_IGNORE_GUNFRAMES;
258  if (client->settings[CLS_NOGUN] != 2) {
259  psFlags |= MSG_PS_IGNORE_GUNINDEX;
260  }
261  }
262  if (client->settings[CLS_NOBLEND]) {
263  psFlags |= MSG_PS_IGNORE_BLEND;
264  }
265  if (frame->ps.pmove.pm_type < PM_DEAD) {
266  if (!(frame->ps.pmove.pm_flags & PMF_NO_PREDICTION)) {
267  psFlags |= MSG_PS_IGNORE_VIEWANGLES;
268  }
269  } else {
270  // lying dead on a rotating platform?
271  psFlags |= MSG_PS_IGNORE_DELTAANGLES;
272  }
273  }
274 
275  clientEntityNum = 0;
276  if (client->protocol == PROTOCOL_VERSION_Q2PRO) {
277  if (frame->ps.pmove.pm_type < PM_DEAD && !client->settings[CLS_RECORDING]) {
278  clientEntityNum = frame->clientNum + 1;
279  }
280  if (client->settings[CLS_NOPREDICT]) {
281  psFlags |= MSG_PS_IGNORE_PREDICTION;
282  }
283  suppressed = client->frameflags;
284  } else {
285  suppressed = client->suppress_count;
286  }
287 
288  // delta encode the playerstate
289  extraflags = MSG_WriteDeltaPlayerstate_Enhanced(oldstate, &frame->ps, psFlags);
290 
291  if (client->protocol == PROTOCOL_VERSION_Q2PRO) {
292  // delta encode the clientNum
293  if (client->version < PROTOCOL_VERSION_Q2PRO_CLIENTNUM_FIX) {
294  if (!oldframe || frame->clientNum != oldframe->clientNum) {
295  extraflags |= EPS_CLIENTNUM;
296  MSG_WriteByte(frame->clientNum);
297  }
298  } else {
299  int clientNum = oldframe ? oldframe->clientNum : 0;
300  if (clientNum != frame->clientNum) {
301  extraflags |= EPS_CLIENTNUM;
302  MSG_WriteByte(frame->clientNum);
303  }
304  }
305  }
306 
307  // save 3 high bits of extraflags
308  *b1 = svc_frame | (((extraflags & 0x70) << 1));
309 
310  // save 4 low bits of extraflags
311  *b2 = (suppressed & SUPPRESSCOUNT_MASK) |
312  ((extraflags & 0x0F) << SUPPRESSCOUNT_BITS);
313 
314  client->suppress_count = 0;
315  client->frameflags = 0;
316 
317  // delta encode the entities
318  SV_EmitPacketEntities(client, oldframe, frame, clientEntityNum);
319 }

Referenced by SVC_DirectConnect().

client_s::lastframe
int lastframe
Definition: server.h:290
server_static_s::next_entity
unsigned next_entity
Definition: server.h:459
nullEntityState
const entity_packed_t nullEntityState
Definition: msg.c:40
SV_BASELINES_MASK
#define SV_BASELINES_MASK
Definition: server.h:70
get_last_frame
static client_frame_t * get_last_frame(client_t *client)
Definition: entities.c:134
client_frame_t::first_entity
unsigned first_entity
Definition: server.h:102
sv_novis
cvar_t * sv_novis
Definition: main.c:56
svs
server_static_t svs
Definition: init.c:21
maxclients
cvar_t * maxclients
Definition: g_main.c:42
client_s::protocol
int protocol
Definition: server.h:324
server_static_s::entities
entity_packed_t * entities
Definition: server.h:460
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
BSP_ClusterVis
byte * BSP_ClusterVis(bsp_t *bsp, byte *mask, int cluster, int vis)
Definition: bsp.c:1339
client_s::number
int number
Definition: server.h:262
client_s::frames_sent
unsigned frames_sent
Definition: server.h:302
SV_BASELINES_SHIFT
#define SV_BASELINES_SHIFT
Definition: server.h:68
server_entity_t::solid32
int solid32
Definition: server.h:112
client_s::suppress_count
int suppress_count
Definition: server.h:311
MSG_WriteByte
void MSG_WriteByte(int c)
Definition: msg.c:107
SV_EmitPacketEntities
static void SV_EmitPacketEntities(client_t *client, client_frame_t *from, client_frame_t *to, int clientEntityNum)
Definition: entities.c:41
client_s::last_valid_cluster
int last_valid_cluster
Definition: server.h:362
client_frame_t::clientNum
int clientNum
Definition: server.h:104
client_frame_t::areabytes
int areabytes
Definition: server.h:105
CM_AreasConnected
qboolean CM_AreasConnected(cm_t *cm, int area1, int area2)
Definition: cmodel.c:890
client_frame_t::num_entities
unsigned num_entities
Definition: server.h:101
SZ_GetSpace
void * SZ_GetSpace(sizebuf_t *buf, size_t len)
Definition: sizebuf.c:48
MSG_PackEntity
void MSG_PackEntity(entity_packed_t *out, const entity_state_t *in, qboolean short_angles)
Definition: msg.c:468
EDICT_POOL
#define EDICT_POOL(c, n)
Definition: server.h:171
CM_FatPVS
byte * CM_FatPVS(cm_t *cm, byte *mask, const vec3_t org, int vis)
Definition: cmodel.c:1045
MSG_WriteDeltaPlayerstate_Enhanced
int MSG_WriteDeltaPlayerstate_Enhanced(const player_packed_t *from, player_packed_t *to, msgPsFlags_t flags)
Definition: msg.c:975
MSG_PackPlayer
void MSG_PackPlayer(player_packed_t *out, const player_state_t *in)
Definition: msg.c:763
sv
server_t sv
Definition: init.c:22
client_s::baselines
entity_packed_t * baselines[SV_BASELINES_CHUNKS]
Definition: server.h:340
msg_write
sizebuf_t msg_write
Definition: msg.c:34
client_s::frames
client_frame_t frames[UPDATE_BACKUP]
Definition: server.h:301
CM_WriteAreaBits
int CM_WriteAreaBits(cm_t *cm, byte *buffer, int area)
Definition: cmodel.c:925
MSG_WriteDeltaEntity
void MSG_WriteDeltaEntity(const entity_packed_t *from, const entity_packed_t *to, msgEsFlags_t flags)
Definition: msg.c:505
client_frame_t::sentTime
unsigned sentTime
Definition: server.h:107
client_s::version
int version
Definition: server.h:325
client_frame_t::latency
int latency
Definition: server.h:108
client_frame_t
Definition: server.h:99
MSG_WriteShort
void MSG_WriteShort(int c)
Definition: msg.c:125
client_frame_t::ps
player_packed_t ps
Definition: server.h:103
server_static_s::num_entities
unsigned num_entities
Definition: server.h:458
client_frame_t::number
int number
Definition: server.h:100
Q2PRO_OPTIMIZE
#define Q2PRO_OPTIMIZE(c)
Definition: entities.c:31
MSG_WriteLong
void MSG_WriteLong(int c)
Definition: msg.c:144
Q2PRO_SHORTANGLES
#define Q2PRO_SHORTANGLES(c, e)
Definition: server.h:179
CM_PointLeaf
mleaf_t * CM_PointLeaf(cm_t *cm, vec3_t p)
Definition: cmodel.c:209
client_s::settings
int settings[CLS_MAX]
Definition: server.h:326
g_features
cvar_t * g_features
Definition: main.c:99
client_s::pool
edict_pool_t * pool
Definition: server.h:345
server_t::state
server_state_t state
Definition: server.h:146
client_s::frameflags
unsigned frameflags
Definition: server.h:307
server_t::entities
server_entity_t entities[MAX_EDICTS]
Definition: server.h:166
client_frame_t::areabits
byte areabits[MAX_MAP_AREA_BYTES]
Definition: server.h:106
SV_EdictIsVisible
qboolean SV_EdictIsVisible(cm_t *cm, edict_t *ent, byte *mask)
Definition: world.c:129
client_s::framenum
int framenum
Definition: server.h:303
client_s::cm
cm_t * cm
Definition: server.h:346
client_s::esFlags
msgEsFlags_t esFlags
Definition: server.h:329
com_eventTime
unsigned com_eventTime
Definition: common.c:122
client_s::frames_nodelta
unsigned frames_nodelta
Definition: server.h:302
MSG_WriteDeltaPlayerstate_Default
void MSG_WriteDeltaPlayerstate_Default(const player_packed_t *from, const player_packed_t *to)
Definition: msg.c:795
client_s::name
char name[MAX_CLIENT_NAME]
Definition: server.h:276
client_s::edict
edict_t * edict
Definition: server.h:261