2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 extern cvar_t sv_airaccel_qw_stretchfactor;
25 extern cvar_t sv_qcstats;
26 extern cvar_t sv_warsowbunny_airforwardaccel;
27 extern cvar_t sv_warsowbunny_accel;
28 extern cvar_t sv_warsowbunny_topspeed;
29 extern cvar_t sv_warsowbunny_turnaccel;
30 extern cvar_t sv_warsowbunny_backtosideratio;
31 extern cvar_t sv_onlycsqcnetworking;
32 extern cvar_t sv_cullentities_trace_entityocclusion;
33 extern cvar_t sv_cullentities_trace_samples_players;
34 extern cvar_t sv_cullentities_trace_eyejitter;
35 extern cvar_t sv_cullentities_trace_expand;
36 extern cvar_t sv_cullentities_trace_delay_players;
37 extern cvar_t sv_cullentities_trace_spectators;
40 =============================================================================
44 =============================================================================
51 Sends text across to be displayed
52 FIXME: make this just a stuffed echo?
55 void SV_ClientPrint(const char *msg)
57 if (host_client->netconnection)
59 MSG_WriteByte(&host_client->netconnection->message, svc_print);
60 MSG_WriteString(&host_client->netconnection->message, msg);
68 Sends text across to be displayed
69 FIXME: make this just a stuffed echo?
72 void SV_ClientPrintf(const char *fmt, ...)
75 char msg[MAX_INPUTLINE];
78 dpvsnprintf(msg,sizeof(msg),fmt,argptr);
88 Sends text to all active clients
91 void SV_BroadcastPrint(const char *msg)
96 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
98 if (client->active && client->netconnection)
100 MSG_WriteByte(&client->netconnection->message, svc_print);
101 MSG_WriteString(&client->netconnection->message, msg);
105 if (sv_echobprint.integer && !host_isclient.integer)
113 Sends text to all active clients
116 void SV_BroadcastPrintf(const char *fmt, ...)
119 char msg[MAX_INPUTLINE];
121 va_start(argptr,fmt);
122 dpvsnprintf(msg,sizeof(msg),fmt,argptr);
125 SV_BroadcastPrint(msg);
132 Send text over to the client to be executed
135 void SV_ClientCommands(const char *fmt, ...)
138 char string[MAX_INPUTLINE];
140 if (!host_client->netconnection)
143 va_start(argptr,fmt);
144 dpvsnprintf(string, sizeof(string), fmt, argptr);
147 MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
148 MSG_WriteString(&host_client->netconnection->message, string);
155 Make sure the event gets sent to all clients
158 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
162 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
164 MSG_WriteByte (&sv.datagram, svc_particle);
165 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
166 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
167 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
168 for (i=0 ; i<3 ; i++)
169 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
170 MSG_WriteByte (&sv.datagram, count);
171 MSG_WriteByte (&sv.datagram, color);
172 SV_FlushBroadcastMessages();
179 Make sure the event gets sent to all clients
182 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
184 if (modelindex >= 256 || startframe >= 256)
186 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
188 MSG_WriteByte (&sv.datagram, svc_effect2);
189 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
190 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
191 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
192 MSG_WriteShort (&sv.datagram, modelindex);
193 MSG_WriteShort (&sv.datagram, startframe);
194 MSG_WriteByte (&sv.datagram, framecount);
195 MSG_WriteByte (&sv.datagram, framerate);
199 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
201 MSG_WriteByte (&sv.datagram, svc_effect);
202 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
203 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
204 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
205 MSG_WriteByte (&sv.datagram, modelindex);
206 MSG_WriteByte (&sv.datagram, startframe);
207 MSG_WriteByte (&sv.datagram, framecount);
208 MSG_WriteByte (&sv.datagram, framerate);
210 SV_FlushBroadcastMessages();
217 Each entity can have eight independant sound sources, like voice,
220 Channel 0 is an auto-allocate channel, the others override anything
221 already running on that entity/channel pair.
223 An attenuation of 0 will play full volume everywhere in the level.
224 Larger attenuations will drop off. (max 4 attenuation)
228 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int nvolume, float attenuation, qbool reliable, float speed)
230 prvm_prog_t *prog = SVVM_prog;
232 int sound_num, field_mask, i, ent, speed4000;
234 dest = (reliable ? &sv.reliable_datagram : &sv.datagram);
236 if (nvolume < 0 || nvolume > 255)
238 Con_Printf ("SV_StartSound: volume = %i\n", nvolume);
242 if (attenuation < 0 || attenuation > 4)
244 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
248 if (!IS_CHAN(channel))
250 Con_Printf ("SV_StartSound: channel = %i\n", channel);
254 channel = CHAN_ENGINE2NET(channel);
256 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
259 // find precache number for sound
260 sound_num = SV_SoundIndex(sample, 1);
264 ent = PRVM_NUM_FOR_EDICT(entity);
266 speed4000 = (int)floor(speed * 4000.0f + 0.5f);
268 if (nvolume != DEFAULT_SOUND_PACKET_VOLUME)
269 field_mask |= SND_VOLUME;
270 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
271 field_mask |= SND_ATTENUATION;
272 if (speed4000 && speed4000 != 4000)
273 field_mask |= SND_SPEEDUSHORT4000;
274 if (ent >= 8192 || channel < 0 || channel > 7)
275 field_mask |= SND_LARGEENTITY;
276 if (sound_num >= 256)
277 field_mask |= SND_LARGESOUND;
279 // directed messages go only to the entity they are targeted on
280 MSG_WriteByte (dest, svc_sound);
281 MSG_WriteByte (dest, field_mask);
282 if (field_mask & SND_VOLUME)
283 MSG_WriteByte (dest, nvolume);
284 if (field_mask & SND_ATTENUATION)
285 MSG_WriteByte (dest, (int)(attenuation*64));
286 if (field_mask & SND_SPEEDUSHORT4000)
287 MSG_WriteShort (dest, speed4000);
288 if (field_mask & SND_LARGEENTITY)
290 MSG_WriteShort (dest, ent);
291 MSG_WriteChar (dest, channel);
294 MSG_WriteShort (dest, (ent<<3) | channel);
295 if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
296 MSG_WriteShort (dest, sound_num);
298 MSG_WriteByte (dest, sound_num);
299 for (i = 0;i < 3;i++)
300 MSG_WriteCoord (dest, PRVM_serveredictvector(entity, origin)[i]+0.5*(PRVM_serveredictvector(entity, mins)[i]+PRVM_serveredictvector(entity, maxs)[i]), sv.protocol);
302 // TODO do we have to do anything here when dest is &sv.reliable_datagram?
304 SV_FlushBroadcastMessages();
311 Nearly the same logic as SV_StartSound, except an origin
312 instead of an entity is provided and channel is omitted.
314 The entity sent to the client is 0 (world) and the channel
315 is 0 (CHAN_AUTO). SND_LARGEENTITY will never occur in this
316 function, therefore the check for it is omitted.
320 void SV_StartPointSound (vec3_t origin, const char *sample, int nvolume, float attenuation, float speed)
322 int sound_num, field_mask, i, speed4000;
324 if (nvolume < 0 || nvolume > 255)
326 Con_Printf ("SV_StartPointSound: volume = %i\n", nvolume);
330 if (attenuation < 0 || attenuation > 4)
332 Con_Printf ("SV_StartPointSound: attenuation = %f\n", attenuation);
336 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
339 // find precache number for sound
340 sound_num = SV_SoundIndex(sample, 1);
344 speed4000 = (int)(speed * 40.0f);
346 if (nvolume != DEFAULT_SOUND_PACKET_VOLUME)
347 field_mask |= SND_VOLUME;
348 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
349 field_mask |= SND_ATTENUATION;
350 if (sound_num >= 256)
351 field_mask |= SND_LARGESOUND;
352 if (speed4000 && speed4000 != 4000)
353 field_mask |= SND_SPEEDUSHORT4000;
355 // directed messages go only to the entity they are targeted on
356 MSG_WriteByte (&sv.datagram, svc_sound);
357 MSG_WriteByte (&sv.datagram, field_mask);
358 if (field_mask & SND_VOLUME)
359 MSG_WriteByte (&sv.datagram, nvolume);
360 if (field_mask & SND_ATTENUATION)
361 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
362 if (field_mask & SND_SPEEDUSHORT4000)
363 MSG_WriteShort (&sv.datagram, speed4000);
364 // Always write entnum 0 for the world entity
365 MSG_WriteShort (&sv.datagram, (0<<3) | 0);
366 if (field_mask & SND_LARGESOUND)
367 MSG_WriteShort (&sv.datagram, sound_num);
369 MSG_WriteByte (&sv.datagram, sound_num);
370 for (i = 0;i < 3;i++)
371 MSG_WriteCoord (&sv.datagram, origin[i], sv.protocol);
372 SV_FlushBroadcastMessages();
376 ===============================================================================
380 ===============================================================================
384 =============================================================================
386 The PVS must include a small area around the client to allow head bobbing
387 or other small motion on the client side. Otherwise, a bob might cause an
388 entity that should be visible to not show up, especially when the bob
391 =============================================================================
394 static qbool SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int enumber)
396 prvm_prog_t *prog = SVVM_prog;
398 unsigned int sendflags;
399 unsigned int version;
400 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
401 unsigned int customizeentityforclient;
402 unsigned int sendentity;
405 vec3_t cullmins, cullmaxs;
408 // fast path for games that do not use legacy entity networking
409 // note: still networks clients even if they are legacy
410 sendentity = PRVM_serveredictfunction(ent, SendEntity);
411 if (sv_onlycsqcnetworking.integer && !sendentity && enumber > svs.maxclients)
414 // this 2 billion unit check is actually to detect NAN origins
415 // (we really don't want to send those)
416 if (!(VectorLength2(PRVM_serveredictvector(ent, origin)) < 2000000000.0*2000000000.0))
419 // EF_NODRAW prevents sending for any reason except for your own
420 // client, so we must keep all clients in this superset
421 effects = (unsigned)PRVM_serveredictfloat(ent, effects);
423 // we can omit invisible entities with no effects that are not clients
424 // LadyHavoc: this could kill tags attached to an invisible entity, I
425 // just hope we never have to support that case
426 i = (int)PRVM_serveredictfloat(ent, modelindex);
427 modelindex = (i >= 1 && i < MAX_MODELS && PRVM_serveredictstring(ent, model) && *PRVM_GetString(prog, PRVM_serveredictstring(ent, model)) && sv.models[i]) ? i : 0;
430 i = (int)(PRVM_serveredictfloat(ent, glow_size) * 0.25f);
431 glowsize = (unsigned char)bound(0, i, 255);
432 if (PRVM_serveredictfloat(ent, glow_trail))
433 flags |= RENDER_GLOWTRAIL;
434 if (PRVM_serveredictedict(ent, viewmodelforclient))
435 flags |= RENDER_VIEWMODEL;
437 v = PRVM_serveredictvector(ent, color);
439 light[0] = (unsigned short)bound(0, f, 65535);
441 light[1] = (unsigned short)bound(0, f, 65535);
443 light[2] = (unsigned short)bound(0, f, 65535);
444 f = PRVM_serveredictfloat(ent, light_lev);
445 light[3] = (unsigned short)bound(0, f, 65535);
446 lightstyle = (unsigned char)PRVM_serveredictfloat(ent, style);
447 lightpflags = (unsigned char)PRVM_serveredictfloat(ent, pflags);
449 if (gamemode == GAME_TENEBRAE)
451 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
455 lightpflags |= PFLAGS_FULLDYNAMIC;
457 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
461 light[0] = (int)(0.2*256);
462 light[1] = (int)(1.0*256);
463 light[2] = (int)(0.2*256);
465 lightpflags |= PFLAGS_FULLDYNAMIC;
469 specialvisibilityradius = 0;
470 if (lightpflags & PFLAGS_FULLDYNAMIC)
471 specialvisibilityradius = max(specialvisibilityradius, light[3]);
473 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
474 if (flags & RENDER_GLOWTRAIL)
475 specialvisibilityradius = max(specialvisibilityradius, 100);
476 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
478 if (effects & EF_BRIGHTFIELD)
479 specialvisibilityradius = max(specialvisibilityradius, 80);
480 if (effects & EF_MUZZLEFLASH)
481 specialvisibilityradius = max(specialvisibilityradius, 100);
482 if (effects & EF_BRIGHTLIGHT)
483 specialvisibilityradius = max(specialvisibilityradius, 400);
484 if (effects & EF_DIMLIGHT)
485 specialvisibilityradius = max(specialvisibilityradius, 200);
486 if (effects & EF_RED)
487 specialvisibilityradius = max(specialvisibilityradius, 200);
488 if (effects & EF_BLUE)
489 specialvisibilityradius = max(specialvisibilityradius, 200);
490 if (effects & EF_FLAME)
491 specialvisibilityradius = max(specialvisibilityradius, 250);
492 if (effects & EF_STARDUST)
493 specialvisibilityradius = max(specialvisibilityradius, 100);
496 // early culling checks
497 // (final culling is done by SV_MarkWriteEntityStateToClient)
498 customizeentityforclient = PRVM_serveredictfunction(ent, customizeentityforclient);
499 if (!customizeentityforclient && enumber > svs.maxclients && (!modelindex && !specialvisibilityradius))
503 cs->active = ACTIVE_NETWORK;
504 cs->number = enumber;
505 VectorCopy(PRVM_serveredictvector(ent, origin), cs->origin);
506 VectorCopy(PRVM_serveredictvector(ent, angles), cs->angles);
508 cs->effects = effects;
509 cs->colormap = (unsigned)PRVM_serveredictfloat(ent, colormap);
510 cs->modelindex = modelindex;
511 cs->skin = (unsigned)PRVM_serveredictfloat(ent, skin);
512 cs->frame = (unsigned)PRVM_serveredictfloat(ent, frame);
513 cs->viewmodelforclient = PRVM_serveredictedict(ent, viewmodelforclient);
514 cs->exteriormodelforclient = PRVM_serveredictedict(ent, exteriormodeltoclient);
515 cs->nodrawtoclient = PRVM_serveredictedict(ent, nodrawtoclient);
516 cs->drawonlytoclient = PRVM_serveredictedict(ent, drawonlytoclient);
517 cs->customizeentityforclient = customizeentityforclient;
518 cs->tagentity = PRVM_serveredictedict(ent, tag_entity);
519 cs->tagindex = (unsigned char)PRVM_serveredictfloat(ent, tag_index);
520 cs->glowsize = glowsize;
521 cs->traileffectnum = PRVM_serveredictfloat(ent, traileffectnum);
523 // don't need to init cs->colormod because the defaultstate did that for us
524 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
525 v = PRVM_serveredictvector(ent, colormod);
526 if (VectorLength2(v))
528 i = (int)(v[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
529 i = (int)(v[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
530 i = (int)(v[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
533 // don't need to init cs->glowmod because the defaultstate did that for us
534 //cs->glowmod[0] = cs->glowmod[1] = cs->glowmod[2] = 32;
535 v = PRVM_serveredictvector(ent, glowmod);
536 if (VectorLength2(v))
538 i = (int)(v[0] * 32.0f);cs->glowmod[0] = bound(0, i, 255);
539 i = (int)(v[1] * 32.0f);cs->glowmod[1] = bound(0, i, 255);
540 i = (int)(v[2] * 32.0f);cs->glowmod[2] = bound(0, i, 255);
543 cs->modelindex = modelindex;
546 f = (PRVM_serveredictfloat(ent, alpha) * 255.0f);
550 cs->alpha = (unsigned char)bound(0, i, 255);
553 f = (PRVM_serveredictfloat(ent, renderamt));
557 cs->alpha = (unsigned char)bound(0, i, 255);
561 f = (PRVM_serveredictfloat(ent, scale) * 16.0f);
565 cs->scale = (unsigned char)bound(0, i, 255);
569 f = PRVM_serveredictfloat(ent, glow_color);
571 cs->glowcolor = (int)f;
573 if (PRVM_serveredictfloat(ent, fullbright))
574 cs->effects |= EF_FULLBRIGHT;
576 f = PRVM_serveredictfloat(ent, modelflags);
578 cs->effects |= ((unsigned int)f & 0xff) << 24;
580 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_STEP)
581 cs->flags |= RENDER_STEP;
582 if (cs->number != sv.writeentitiestoclient_cliententitynumber && (cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
583 cs->flags |= RENDER_LOWPRECISION;
584 if (PRVM_serveredictfloat(ent, colormap) >= 1024)
585 cs->flags |= RENDER_COLORMAPPED;
586 if (cs->viewmodelforclient)
587 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
589 if (PRVM_serveredictfloat(ent, sendcomplexanimation))
591 cs->flags |= RENDER_COMPLEXANIMATION;
592 if (PRVM_serveredictfloat(ent, skeletonindex) >= 1)
593 cs->skeletonobject = ent->priv.server->skeleton;
594 cs->framegroupblend[0].frame = PRVM_serveredictfloat(ent, frame);
595 cs->framegroupblend[1].frame = PRVM_serveredictfloat(ent, frame2);
596 cs->framegroupblend[2].frame = PRVM_serveredictfloat(ent, frame3);
597 cs->framegroupblend[3].frame = PRVM_serveredictfloat(ent, frame4);
598 cs->framegroupblend[0].start = PRVM_serveredictfloat(ent, frame1time);
599 cs->framegroupblend[1].start = PRVM_serveredictfloat(ent, frame2time);
600 cs->framegroupblend[2].start = PRVM_serveredictfloat(ent, frame3time);
601 cs->framegroupblend[3].start = PRVM_serveredictfloat(ent, frame4time);
602 cs->framegroupblend[1].lerp = PRVM_serveredictfloat(ent, lerpfrac);
603 cs->framegroupblend[2].lerp = PRVM_serveredictfloat(ent, lerpfrac3);
604 cs->framegroupblend[3].lerp = PRVM_serveredictfloat(ent, lerpfrac4);
605 cs->framegroupblend[0].lerp = 1.0f - cs->framegroupblend[1].lerp - cs->framegroupblend[2].lerp - cs->framegroupblend[3].lerp;
606 cs->frame = 0; // don't need the legacy frame
609 cs->light[0] = light[0];
610 cs->light[1] = light[1];
611 cs->light[2] = light[2];
612 cs->light[3] = light[3];
613 cs->lightstyle = lightstyle;
614 cs->lightpflags = lightpflags;
616 cs->specialvisibilityradius = specialvisibilityradius;
618 // calculate the visible box of this entity (don't use the physics box
619 // as that is often smaller than a model, and would not count
620 // specialvisibilityradius)
621 if ((model = SV_GetModelByIndex(modelindex)) && (model->type != mod_null))
623 float scale = cs->scale * (1.0f / 16.0f);
624 if (cs->angles[0] || cs->angles[2]) // pitch and roll
626 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
627 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
629 else if (cs->angles[1] || ((effects | model->effects) & EF_ROTATE))
631 VectorMA(cs->origin, scale, model->yawmins, cullmins);
632 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
636 VectorMA(cs->origin, scale, model->normalmins, cullmins);
637 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
642 // if there is no model (or it could not be loaded), use the physics box
643 VectorAdd(cs->origin, PRVM_serveredictvector(ent, mins), cullmins);
644 VectorAdd(cs->origin, PRVM_serveredictvector(ent, maxs), cullmaxs);
646 if (specialvisibilityradius)
648 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
649 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
650 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
651 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
652 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
653 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
656 // calculate center of bbox for network prioritization purposes
657 VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
659 // if culling box has moved, update pvs cluster links
660 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
662 VectorCopy(cullmins, ent->priv.server->cullmins);
663 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
664 // a value of -1 for pvs_numclusters indicates that the links are not
665 // cached, and should be re-tested each time, this is the case if the
666 // culling box touches too many pvs clusters to store, or if the world
667 // model does not support FindBoxClusters
668 ent->priv.server->pvs_numclusters = -1;
669 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
671 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
672 if (i <= MAX_ENTITYCLUSTERS)
673 ent->priv.server->pvs_numclusters = i;
677 // we need to do some csqc entity upkeep here
678 // get self.SendFlags and clear them
679 // (to let the QC know that they've been read)
682 sendflags = (unsigned int)PRVM_serveredictfloat(ent, SendFlags);
683 PRVM_serveredictfloat(ent, SendFlags) = 0;
684 // legacy self.Version system
685 if ((version = (unsigned int)PRVM_serveredictfloat(ent, Version)))
687 if (sv.csqcentityversion[enumber] != version)
688 sendflags = 0xFFFFFF;
689 sv.csqcentityversion[enumber] = version;
691 // move sendflags into the per-client sendflags
693 for (i = 0;i < svs.maxclients;i++)
694 svs.clients[i].csqcentitysendflags[enumber] |= sendflags;
695 // mark it as inactive for non-csqc networking
696 cs->active = ACTIVE_SHARED;
702 static void SV_PrepareEntitiesForSending(void)
704 prvm_prog_t *prog = SVVM_prog;
707 // send all entities that touch the pvs
708 sv.numsendentities = 0;
709 sv.sendentitiesindex[0] = NULL;
710 memset(sv.sendentitiesindex, 0, prog->num_edicts * sizeof(*sv.sendentitiesindex));
711 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
713 if (!ent->free && SV_PrepareEntityForSending(ent, sv.sendentities + sv.numsendentities, e))
715 sv.sendentitiesindex[e] = sv.sendentities + sv.numsendentities;
716 sv.numsendentities++;
721 #define MAX_LINEOFSIGHTTRACES 64
723 qbool SV_CanSeeBox(int numtraces, vec_t eyejitter, vec_t enlarge, vec_t entboxexpand, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
725 prvm_prog_t *prog = SVVM_prog;
728 float starttransformed[3], endtransformed[3];
729 float boxminstransformed[3], boxmaxstransformed[3];
730 float localboxcenter[3], localboxextents[3], localboxmins[3], localboxmaxs[3];
733 int originalnumtouchedicts;
734 int numtouchedicts = 0;
736 matrix4x4_t matrix, imatrix;
739 static prvm_edict_t *touchedicts[MAX_EDICTS];
740 vec3_t eyemins, eyemaxs, start;
741 vec3_t boxmins, boxmaxs;
742 vec3_t clipboxmins, clipboxmaxs;
743 vec3_t endpoints[MAX_LINEOFSIGHTTRACES];
745 numtraces = min(numtraces, MAX_LINEOFSIGHTTRACES);
747 // jitter the eye location within this box
748 eyemins[0] = eye[0] - eyejitter;
749 eyemaxs[0] = eye[0] + eyejitter;
750 eyemins[1] = eye[1] - eyejitter;
751 eyemaxs[1] = eye[1] + eyejitter;
752 eyemins[2] = eye[2] - eyejitter;
753 eyemaxs[2] = eye[2] + eyejitter;
754 // expand the box a little
755 boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0] - entboxexpand;
756 boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0] + entboxexpand;
757 boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1] - entboxexpand;
758 boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1] + entboxexpand;
759 boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2] - entboxexpand;
760 boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2] + entboxexpand;
762 VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, endpoints[0]);
763 for (traceindex = 1;traceindex < numtraces;traceindex++)
764 VectorSet(endpoints[traceindex], lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
766 // calculate sweep box for the entire swarm of traces
767 VectorCopy(eyemins, clipboxmins);
768 VectorCopy(eyemaxs, clipboxmaxs);
769 for (traceindex = 0;traceindex < numtraces;traceindex++)
771 clipboxmins[0] = min(clipboxmins[0], endpoints[traceindex][0]);
772 clipboxmins[1] = min(clipboxmins[1], endpoints[traceindex][1]);
773 clipboxmins[2] = min(clipboxmins[2], endpoints[traceindex][2]);
774 clipboxmaxs[0] = max(clipboxmaxs[0], endpoints[traceindex][0]);
775 clipboxmaxs[1] = max(clipboxmaxs[1], endpoints[traceindex][1]);
776 clipboxmaxs[2] = max(clipboxmaxs[2], endpoints[traceindex][2]);
779 // get the list of entities in the sweep box
780 if (sv_cullentities_trace_entityocclusion.integer)
781 numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
782 if (numtouchedicts > MAX_EDICTS)
784 // this never happens
785 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
786 numtouchedicts = MAX_EDICTS;
788 // iterate the entities found in the sweep box and filter them
789 originalnumtouchedicts = numtouchedicts;
791 for (touchindex = 0;touchindex < originalnumtouchedicts;touchindex++)
793 touch = touchedicts[touchindex];
794 if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
796 model = SV_GetModelFromEdict(touch);
797 if (!model || !model->brush.TraceLineOfSight)
799 // skip obviously transparent entities
800 alpha = PRVM_serveredictfloat(touch, alpha);
801 if (alpha && alpha < 1)
803 if ((int)PRVM_serveredictfloat(touch, effects) & EF_ADDITIVE)
805 touchedicts[numtouchedicts++] = touch;
808 // now that we have a filtered list of "interesting" entities, fire each
809 // ray against all of them, this gives us an early-out case when something
810 // is visible (which it often is)
812 for (traceindex = 0;traceindex < numtraces;traceindex++)
814 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
815 // check world occlusion
816 if (sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight)
817 if (!sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, start, endpoints[traceindex], boxmins, boxmaxs))
819 for (touchindex = 0;touchindex < numtouchedicts;touchindex++)
821 touch = touchedicts[touchindex];
822 model = SV_GetModelFromEdict(touch);
823 if(model && model->brush.TraceLineOfSight)
825 // get the entity matrix
826 pitchsign = SV_GetPitchSign(prog, touch);
827 Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
828 Matrix4x4_Invert_Simple(&imatrix, &matrix);
829 // see if the ray hits this entity
830 Matrix4x4_Transform(&imatrix, start, starttransformed);
831 Matrix4x4_Transform(&imatrix, endpoints[traceindex], endtransformed);
832 Matrix4x4_Transform(&imatrix, boxmins, boxminstransformed);
833 Matrix4x4_Transform(&imatrix, boxmaxs, boxmaxstransformed);
834 // transform the AABB to local space
835 VectorMAM(0.5f, boxminstransformed, 0.5f, boxmaxstransformed, localboxcenter);
836 localboxextents[0] = fabs(boxmaxstransformed[0] - localboxcenter[0]);
837 localboxextents[1] = fabs(boxmaxstransformed[1] - localboxcenter[1]);
838 localboxextents[2] = fabs(boxmaxstransformed[2] - localboxcenter[2]);
839 localboxmins[0] = localboxcenter[0] - localboxextents[0];
840 localboxmins[1] = localboxcenter[1] - localboxextents[1];
841 localboxmins[2] = localboxcenter[2] - localboxextents[2];
842 localboxmaxs[0] = localboxcenter[0] + localboxextents[0];
843 localboxmaxs[1] = localboxcenter[1] + localboxextents[1];
844 localboxmaxs[2] = localboxcenter[2] + localboxextents[2];
845 if (!model->brush.TraceLineOfSight(model, starttransformed, endtransformed, localboxmins, localboxmaxs))
852 // check if the ray was blocked
853 if (touchindex < numtouchedicts)
855 // return if the ray was not blocked
863 void SV_MarkWriteEntityStateToClient(entity_state_t *s, client_t *client)
865 prvm_prog_t *prog = SVVM_prog;
869 if (sv.sententitiesconsideration[s->number] == sv.sententitiesmark)
871 sv.sententitiesconsideration[s->number] = sv.sententitiesmark;
872 sv.writeentitiestoclient_stats_totalentities++;
874 if (s->customizeentityforclient)
876 PRVM_serverglobalfloat(time) = sv.time;
877 PRVM_serverglobaledict(self) = s->number;
878 PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber;
879 prog->ExecuteProgram(prog, s->customizeentityforclient, "customizeentityforclient: NULL function");
880 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
884 // never reject player
885 if (s->number != sv.writeentitiestoclient_cliententitynumber)
887 // check various rejection conditions
888 if (s->nodrawtoclient == sv.writeentitiestoclient_cliententitynumber)
890 if (s->drawonlytoclient && s->drawonlytoclient != sv.writeentitiestoclient_cliententitynumber)
892 if (s->effects & EF_NODRAW)
894 // LadyHavoc: only send entities with a model or important effects
895 if (!s->modelindex && s->specialvisibilityradius == 0)
898 isbmodel = (model = SV_GetModelByIndex(s->modelindex)) != NULL && model->name[0] == '*';
899 // viewmodels don't have visibility checking
900 if (s->viewmodelforclient)
902 if (s->viewmodelforclient != sv.writeentitiestoclient_cliententitynumber)
905 else if (s->tagentity)
907 // tag attached entities simply check their parent
908 if (!sv.sendentitiesindex[s->tagentity])
910 SV_MarkWriteEntityStateToClient(sv.sendentitiesindex[s->tagentity], client);
911 if (sv.sententities[s->tagentity] != sv.sententitiesmark)
914 // always send world submodels in newer protocols because they don't
915 // generate much traffic (in old protocols they hog bandwidth)
916 // but only if sv_cullentities_nevercullbmodels is off
917 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
919 // entity has survived every check so far, check if visible
920 ed = PRVM_EDICT_NUM(s->number);
922 // if not touching a visible leaf
923 if (sv_cullentities_pvs.integer && !r_novis.integer && !r_trippy.integer && sv.writeentitiestoclient_pvsbytes)
925 if (ed->priv.server->pvs_numclusters < 0)
927 // entity too big for clusters list
928 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv.writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
930 sv.writeentitiestoclient_stats_culled_pvs++;
937 // check cached clusters list
938 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
939 if (CHECKPVSBIT(sv.writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
941 if (i == ed->priv.server->pvs_numclusters)
943 sv.writeentitiestoclient_stats_culled_pvs++;
949 // or not seen by random tracelines
950 if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight && !r_trippy.integer && (client->frags != -666 || sv_cullentities_trace_spectators.integer))
953 s->number <= svs.maxclients
954 ? sv_cullentities_trace_samples_players.integer
956 s->specialvisibilityradius
957 ? sv_cullentities_trace_samples_extra.integer
958 : sv_cullentities_trace_samples.integer;
963 for (eyeindex = 0;eyeindex < sv.writeentitiestoclient_numeyes;eyeindex++)
964 if(SV_CanSeeBox(samples, sv_cullentities_trace_eyejitter.value, sv_cullentities_trace_enlarge.value, sv_cullentities_trace_expand.value, sv.writeentitiestoclient_eyes[eyeindex], ed->priv.server->cullmins, ed->priv.server->cullmaxs))
966 if(eyeindex < sv.writeentitiestoclient_numeyes)
967 svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number] =
969 s->number <= svs.maxclients
970 ? sv_cullentities_trace_delay_players.value
971 : sv_cullentities_trace_delay.value
973 else if ((float)host.realtime > svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number])
975 sv.writeentitiestoclient_stats_culled_trace++;
983 // this just marks it for sending
984 // FIXME: it would be more efficient to send here, but the entity
985 // compressor isn't that flexible
986 sv.writeentitiestoclient_stats_visibleentities++;
987 sv.sententities[s->number] = sv.sententitiesmark;
990 #if MAX_LEVELNETWORKEYES > 0
991 #define MAX_EYE_RECURSION 1 // increase if recursion gets supported by portals
992 void SV_AddCameraEyes(void)
994 prvm_prog_t *prog = SVVM_prog;
997 int cameras[MAX_LEVELNETWORKEYES];
998 vec3_t camera_origins[MAX_LEVELNETWORKEYES];
999 int eye_levels[MAX_CLIENTNETWORKEYES] = {0};
1003 // check line of sight to portal entities and add them to PVS
1004 for (e = 1, ed = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ed = PRVM_NEXT_EDICT(ed))
1008 if(PRVM_serveredictfunction(ed, camera_transform))
1010 PRVM_serverglobalfloat(time) = sv.time;
1011 PRVM_serverglobaledict(self) = e;
1012 PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber;
1013 VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_serverglobalvector(trace_endpos));
1014 VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_G_VECTOR(OFS_PARM0));
1015 VectorClear(PRVM_G_VECTOR(OFS_PARM1));
1016 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ed, camera_transform), "QC function e.camera_transform is missing");
1017 if(!VectorCompare(PRVM_serverglobalvector(trace_endpos), sv.writeentitiestoclient_eyes[0]))
1019 VectorCopy(PRVM_serverglobalvector(trace_endpos), camera_origins[n_cameras]);
1020 cameras[n_cameras] = e;
1022 if(n_cameras >= MAX_LEVELNETWORKEYES)
1032 // i is loop counter, is reset to 0 when an eye got added
1033 // j is camera index to check
1034 for(i = 0, j = 0; sv.writeentitiestoclient_numeyes < MAX_CLIENTNETWORKEYES && i < n_cameras; ++i, ++j, j %= n_cameras)
1038 ed = PRVM_EDICT_NUM(cameras[j]);
1039 VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, mins), mi);
1040 VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, maxs), ma);
1041 for(k = 0; k < sv.writeentitiestoclient_numeyes; ++k)
1042 if(eye_levels[k] <= MAX_EYE_RECURSION)
1044 if(SV_CanSeeBox(sv_cullentities_trace_samples_extra.integer, sv_cullentities_trace_eyejitter.value, sv_cullentities_trace_enlarge.value, sv_cullentities_trace_expand.value, sv.writeentitiestoclient_eyes[k], mi, ma))
1045 svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[cameras[j]] = host.realtime + sv_cullentities_trace_delay.value;
1047 // bones_was_here: this use of visibletime doesn't conflict because sv_cullentities_trace doesn't consider portal entities
1048 // the explicit cast prevents float precision differences that cause the condition to fail
1049 if ((float)host.realtime <= svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[cameras[j]])
1051 eye_levels[sv.writeentitiestoclient_numeyes] = eye_levels[k] + 1;
1052 VectorCopy(camera_origins[j], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
1053 // Con_Printf("added eye %d: %f %f %f because we can see %f %f %f .. %f %f %f from eye %d\n", j, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][0], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][1], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes][2], mi[0], mi[1], mi[2], ma[0], ma[1], ma[2], k);
1054 sv.writeentitiestoclient_numeyes++;
1063 void SV_AddCameraEyes(void)
1074 static void SV_CleanupEnts (void)
1076 prvm_prog_t *prog = SVVM_prog;
1080 ent = PRVM_NEXT_EDICT(prog->edicts);
1081 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1082 PRVM_serveredictfloat(ent, effects) = (int)PRVM_serveredictfloat(ent, effects) & ~EF_MUZZLEFLASH;
1087 SV_WriteClientdataToMessage
1091 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1093 prvm_prog_t *prog = SVVM_prog;
1096 prvm_edict_t *other;
1101 float *statsf = (float *)stats;
1105 // send a damage message
1107 if (PRVM_serveredictfloat(ent, dmg_take) || PRVM_serveredictfloat(ent, dmg_save))
1109 other = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, dmg_inflictor));
1110 MSG_WriteByte (msg, svc_damage);
1111 MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_save));
1112 MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_take));
1113 for (i=0 ; i<3 ; i++)
1114 MSG_WriteCoord (msg, PRVM_serveredictvector(other, origin)[i] + 0.5*(PRVM_serveredictvector(other, mins)[i] + PRVM_serveredictvector(other, maxs)[i]), sv.protocol);
1116 PRVM_serveredictfloat(ent, dmg_take) = 0;
1117 PRVM_serveredictfloat(ent, dmg_save) = 0;
1121 // send the current viewpos offset from the view entity
1123 SV_SetIdealPitch (); // how much to look up / down ideally
1125 // a fixangle might get lost in a dropped packet. Oh well.
1126 if(PRVM_serveredictfloat(ent, fixangle))
1128 // angle fixing was requested by global thinking code...
1129 // so store the current angles for later use
1130 VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles);
1131 host_client->fixangle_angles_set = true;
1133 // and clear fixangle for the next frame
1134 PRVM_serveredictfloat(ent, fixangle) = 0;
1137 if (host_client->fixangle_angles_set)
1139 MSG_WriteByte (msg, svc_setangle);
1140 for (i=0 ; i < 3 ; i++)
1141 MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
1142 host_client->fixangle_angles_set = false;
1145 // the runes are in serverflags, pack them into the items value, also pack
1146 // in the items2 value for mission pack huds
1147 // (used only in the mission packs, which do not use serverflags)
1148 items = (int)PRVM_serveredictfloat(ent, items)
1149 | (((int)PRVM_serveredictfloat(ent, items2) & ((1<<9)-1)) << 23)
1150 | (((int)PRVM_serverglobalfloat(serverflags) & ((1<<4)-1)) << 28);
1152 VectorCopy(PRVM_serveredictvector(ent, punchvector), punchvector);
1154 // cache weapon model name and index in client struct to save time
1155 // (this search can be almost 1% of cpu time!)
1156 s = PRVM_GetString(prog, PRVM_serveredictstring(ent, weaponmodel));
1157 if (strcmp(s, client->weaponmodel))
1159 dp_strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1160 client->weaponmodelindex = SV_ModelIndex(s, 1);
1163 viewzoom = (int)(PRVM_serveredictfloat(ent, viewzoom) * 255.0f);
1169 if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
1170 bits |= SU_ONGROUND;
1171 if (PRVM_serveredictfloat(ent, waterlevel) >= 2)
1173 if (PRVM_serveredictfloat(ent, idealpitch))
1174 bits |= SU_IDEALPITCH;
1176 for (i=0 ; i<3 ; i++)
1178 if (PRVM_serveredictvector(ent, punchangle)[i])
1179 bits |= (SU_PUNCH1<<i);
1180 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3)
1182 bits |= (SU_PUNCHVEC1<<i);
1183 if (PRVM_serveredictvector(ent, velocity)[i])
1184 bits |= (SU_VELOCITY1<<i);
1187 gravity = PRVM_serveredictfloat(ent, gravity);if (!gravity) gravity = 1.0f;
1189 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1190 stats[STAT_VIEWHEIGHT] = (int)PRVM_serveredictvector(ent, view_ofs)[2];
1191 stats[STAT_ITEMS] = items;
1192 stats[STAT_WEAPONFRAME] = (int)PRVM_serveredictfloat(ent, weaponframe);
1193 stats[STAT_ARMOR] = (int)PRVM_serveredictfloat(ent, armorvalue);
1194 stats[STAT_WEAPON] = client->weaponmodelindex;
1195 stats[STAT_HEALTH] = (int)PRVM_serveredictfloat(ent, health);
1196 stats[STAT_AMMO] = (int)PRVM_serveredictfloat(ent, currentammo);
1197 stats[STAT_SHELLS] = (int)PRVM_serveredictfloat(ent, ammo_shells);
1198 stats[STAT_NAILS] = (int)PRVM_serveredictfloat(ent, ammo_nails);
1199 stats[STAT_ROCKETS] = (int)PRVM_serveredictfloat(ent, ammo_rockets);
1200 stats[STAT_CELLS] = (int)PRVM_serveredictfloat(ent, ammo_cells);
1201 stats[STAT_ACTIVEWEAPON] = (int)PRVM_serveredictfloat(ent, weapon);
1202 stats[STAT_VIEWZOOM] = viewzoom;
1203 stats[STAT_TOTALSECRETS] = (int)PRVM_serverglobalfloat(total_secrets);
1204 stats[STAT_TOTALMONSTERS] = (int)PRVM_serverglobalfloat(total_monsters);
1205 // the QC bumps these itself by sending svc_'s, so we have to keep them
1206 // zero or they'll be corrected by the engine
1207 //stats[STAT_SECRETS] = PRVM_serverglobalfloat(found_secrets);
1208 //stats[STAT_MONSTERS] = PRVM_serverglobalfloat(killed_monsters);
1210 if(!sv_qcstats.integer)
1212 statsf[STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR] = sv_airaccel_qw_stretchfactor.value;
1213 statsf[STAT_MOVEVARS_AIRCONTROL_PENALTY] = sv_aircontrol_penalty.value;
1214 statsf[STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW] = sv_airspeedlimit_nonqw.value;
1215 statsf[STAT_MOVEVARS_AIRSTRAFEACCEL_QW] = sv_airstrafeaccel_qw.value;
1216 statsf[STAT_MOVEVARS_AIRCONTROL_POWER] = sv_aircontrol_power.value;
1217 // movement settings for prediction
1218 // note: these are not sent in protocols with lower MAX_CL_STATS limits
1219 stats[STAT_MOVEFLAGS] = MOVEFLAG_VALID
1220 | (sv_gameplayfix_q2airaccelerate.integer ? MOVEFLAG_Q2AIRACCELERATE : 0)
1221 | (sv_gameplayfix_nogravityonground.integer ? MOVEFLAG_NOGRAVITYONGROUND : 0)
1222 | (sv_gameplayfix_gravityunaffectedbyticrate.integer ? MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE : 0)
1224 statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL] = sv_warsowbunny_airforwardaccel.value;
1225 statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL] = sv_warsowbunny_accel.value;
1226 statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED] = sv_warsowbunny_topspeed.value;
1227 statsf[STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL] = sv_warsowbunny_turnaccel.value;
1228 statsf[STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO] = sv_warsowbunny_backtosideratio.value;
1229 statsf[STAT_MOVEVARS_AIRSTOPACCELERATE] = sv_airstopaccelerate.value;
1230 statsf[STAT_MOVEVARS_AIRSTRAFEACCELERATE] = sv_airstrafeaccelerate.value;
1231 statsf[STAT_MOVEVARS_MAXAIRSTRAFESPEED] = sv_maxairstrafespeed.value;
1232 statsf[STAT_MOVEVARS_AIRCONTROL] = sv_aircontrol.value;
1233 statsf[STAT_FRAGLIMIT] = fraglimit.value;
1234 statsf[STAT_TIMELIMIT] = timelimit.value;
1235 statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value;
1236 statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value;
1237 statsf[STAT_MOVEVARS_TICRATE] = sys_ticrate.value;
1238 statsf[STAT_MOVEVARS_TIMESCALE] = host_timescale.value;
1239 statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
1240 statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
1241 statsf[STAT_MOVEVARS_MAXSPEED] = sv_maxspeed.value;
1242 statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_maxspeed.value; // FIXME: QW has a separate cvar for this
1243 statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
1244 statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value;
1245 statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value;
1246 statsf[STAT_MOVEVARS_ENTGRAVITY] = gravity;
1247 statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value;
1248 statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
1249 statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value;
1250 statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value;
1251 statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value;
1252 statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
1255 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1257 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1259 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1260 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1262 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1263 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1264 if (viewzoom != 255)
1265 bits |= SU_VIEWZOOM;
1270 if (bits >= 16777216)
1274 MSG_WriteByte (msg, svc_clientdata);
1275 MSG_WriteShort (msg, bits);
1276 if (bits & SU_EXTEND1)
1277 MSG_WriteByte(msg, bits >> 16);
1278 if (bits & SU_EXTEND2)
1279 MSG_WriteByte(msg, bits >> 24);
1281 if (bits & SU_VIEWHEIGHT)
1282 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1284 if (bits & SU_IDEALPITCH)
1285 MSG_WriteChar (msg, (int)PRVM_serveredictfloat(ent, idealpitch));
1287 for (i=0 ; i<3 ; i++)
1289 if (bits & (SU_PUNCH1<<i))
1291 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1292 MSG_WriteChar(msg, (int)PRVM_serveredictvector(ent, punchangle)[i]);
1294 MSG_WriteAngle16i(msg, PRVM_serveredictvector(ent, punchangle)[i]);
1296 if (bits & (SU_PUNCHVEC1<<i))
1298 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1299 MSG_WriteCoord16i(msg, punchvector[i]);
1301 MSG_WriteCoord32f(msg, punchvector[i]);
1303 if (bits & (SU_VELOCITY1<<i))
1305 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1306 MSG_WriteChar(msg, (int)(PRVM_serveredictvector(ent, velocity)[i] * (1.0f / 16.0f)));
1308 MSG_WriteCoord32f(msg, PRVM_serveredictvector(ent, velocity)[i]);
1312 if (bits & SU_ITEMS)
1313 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1315 if (sv.protocol == PROTOCOL_DARKPLACES5)
1317 if (bits & SU_WEAPONFRAME)
1318 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1319 if (bits & SU_ARMOR)
1320 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1321 if (bits & SU_WEAPON)
1322 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1323 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1324 MSG_WriteShort (msg, stats[STAT_AMMO]);
1325 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1326 MSG_WriteShort (msg, stats[STAT_NAILS]);
1327 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1328 MSG_WriteShort (msg, stats[STAT_CELLS]);
1329 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1330 if (bits & SU_VIEWZOOM)
1331 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1333 else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1335 if (bits & SU_WEAPONFRAME)
1336 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1337 if (bits & SU_ARMOR)
1338 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1339 if (bits & SU_WEAPON)
1341 if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1342 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1344 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1346 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1347 MSG_WriteByte (msg, stats[STAT_AMMO]);
1348 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1349 MSG_WriteByte (msg, stats[STAT_NAILS]);
1350 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1351 MSG_WriteByte (msg, stats[STAT_CELLS]);
1352 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_QUOTH || IS_OLDNEXUIZ_DERIVED(gamemode))
1354 for (i = 0;i < 32;i++)
1355 if (stats[STAT_ACTIVEWEAPON] & (1<<i))
1357 MSG_WriteByte (msg, i);
1360 MSG_WriteByte (msg, stats[STAT_ACTIVEWEAPON]);
1361 if (bits & SU_VIEWZOOM)
1363 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1364 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1366 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1371 void SV_FlushBroadcastMessages(void)
1375 if (sv.datagram.cursize <= 0)
1377 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1379 if (!client->begun || !client->netconnection || client->unreliablemsg.cursize + sv.datagram.cursize > client->unreliablemsg.maxsize || client->unreliablemsg_splitpoints >= (int)(sizeof(client->unreliablemsg_splitpoint)/sizeof(client->unreliablemsg_splitpoint[0])))
1381 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1382 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1384 SZ_Clear(&sv.datagram);
1387 static void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg, int maxsize, int maxsize2)
1389 // scan the splitpoints to find out how many we can fit in
1390 int numsegments, j, split;
1391 if (!client->unreliablemsg_splitpoints)
1393 // always accept the first one if it's within 1024 bytes, this ensures
1394 // that very big datagrams which are over the rate limit still get
1395 // through, just to keep it working
1396 for (numsegments = 1;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1397 if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > maxsize)
1399 // the first segment gets an exemption from the rate limiting, otherwise
1400 // it could get dropped consistently due to a low rate limit
1401 if (numsegments == 1)
1403 // some will fit, so add the ones that will fit
1404 split = client->unreliablemsg_splitpoint[numsegments-1];
1405 // note this discards ones that were accepted by the segments scan but
1406 // can not fit, such as a really huge first one that will never ever
1407 // fit in a packet...
1408 if (msg->cursize + split <= maxsize)
1409 SZ_Write(msg, client->unreliablemsg.data, split);
1410 // remove the part we sent, keeping any remaining data
1411 client->unreliablemsg.cursize -= split;
1412 if (client->unreliablemsg.cursize > 0)
1413 memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
1414 // adjust remaining splitpoints
1415 client->unreliablemsg_splitpoints -= numsegments;
1416 for (j = 0;j < client->unreliablemsg_splitpoints;j++)
1417 client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
1421 =======================
1422 SV_SendClientDatagram
1423 =======================
1425 static void SV_SendClientDatagram (client_t *client)
1427 int clientrate, maxrate, maxsize, maxsize2, downloadsize;
1429 int stats[MAX_CL_STATS];
1430 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE];
1433 // obey rate limit by limiting packet frequency if the packet size
1435 // (usually this is caused by reliable messages)
1436 if (!NetConn_CanSend(client->netconnection))
1439 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1440 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1441 if (sv_maxrate.integer != maxrate)
1442 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1444 // clientrate determines the 'cleartime' of a packet
1445 // (how long to wait before sending another, based on this packet's size)
1446 clientrate = bound(NET_MINRATE, client->rate, maxrate);
1448 switch (sv.protocol)
1450 case PROTOCOL_QUAKE:
1451 case PROTOCOL_QUAKEDP:
1452 case PROTOCOL_NEHAHRAMOVIE:
1453 case PROTOCOL_NEHAHRABJP:
1454 case PROTOCOL_NEHAHRABJP2:
1455 case PROTOCOL_NEHAHRABJP3:
1456 case PROTOCOL_QUAKEWORLD:
1457 // no packet size limit support on Quake protocols because it just
1458 // causes missing entities/effects
1459 // packets are simply sent less often to obey the rate limit
1463 case PROTOCOL_DARKPLACES1:
1464 case PROTOCOL_DARKPLACES2:
1465 case PROTOCOL_DARKPLACES3:
1466 case PROTOCOL_DARKPLACES4:
1467 // no packet size limit support on DP1-4 protocols because they kick
1468 // the client off if they overflow, and miss effects
1469 // packets are simply sent less often to obey the rate limit
1470 maxsize = sizeof(sv_sendclientdatagram_buf);
1471 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1474 // DP5 and later protocols support packet size limiting which is a
1475 // better method than limiting packet frequency as QW does
1477 // at very low rates (or very small sys_ticrate) the packet size is
1478 // not reduced below 128, but packets may be sent less often
1480 // how long are bursts?
1481 timedelta = host_client->rate_burstsize / (double)client->rate;
1483 // how much of the burst do we keep reserved?
1484 timedelta *= 1 - net_burstreserve.value;
1486 // only try to use excess time
1487 timedelta = bound(0, host.realtime - host_client->netconnection->cleartime, timedelta);
1489 // but we know next packet will be in sys_ticrate, so we can use up THAT bandwidth
1490 timedelta += sys_ticrate.value;
1492 // note: packet overhead (not counted in maxsize) is 28 bytes
1493 maxsize = (int)(clientrate * timedelta) - 28;
1495 // put it in sound bounds
1496 maxsize = bound(128, maxsize, 1400);
1499 // csqc entities can easily exceed 128 bytes, so disable throttling in
1500 // mods that use csqc (they are likely to use less bandwidth anyway)
1501 if((net_usesizelimit.integer == 1) ? (sv.csqc_progsize > 0) : (net_usesizelimit.integer < 1))
1507 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !host_limitlocal.integer)
1509 // for good singleplayer, send huge packets
1510 maxsize = sizeof(sv_sendclientdatagram_buf);
1511 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1512 // never limit frequency in singleplayer
1513 clientrate = 1000000000;
1516 // while downloading, limit entity updates to half the packet
1517 // (any leftover space will be used for downloading)
1518 if (host_client->download_file)
1521 msg.data = sv_sendclientdatagram_buf;
1522 msg.maxsize = sizeof(sv_sendclientdatagram_buf);
1524 msg.allowoverflow = false;
1526 if (host_client->begun)
1528 // the player is in the game
1529 MSG_WriteByte (&msg, svc_time);
1530 MSG_WriteFloat (&msg, sv.time);
1532 // add the client specific data to the datagram
1533 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1534 // now update the stats[] array using any registered custom fields
1535 VM_SV_UpdateCustomStats(client, client->edict, &msg, stats);
1536 // set host_client->statsdeltabits
1537 Protocol_UpdateClientStats (stats);
1539 // add as many queued unreliable messages (effects) as we can fit
1540 // limit effects to half of the remaining space
1541 if (client->unreliablemsg.cursize)
1542 SV_WriteUnreliableMessages (client, &msg, maxsize/2, maxsize2);
1544 // now write as many entities as we can fit, and also sends stats
1545 SV_WriteEntitiesToClient (client, client->edict, &msg, maxsize);
1547 else if (host.realtime > client->keepalivetime)
1549 // the player isn't totally in the game yet
1550 // send small keepalive messages if too much time has passed
1551 // (may also be sending downloads)
1552 client->keepalivetime = host.realtime + 5;
1553 MSG_WriteChar (&msg, svc_nop);
1556 // if a download is active, see if there is room to fit some download data
1558 downloadsize = min(maxsize*2,maxsize2) - msg.cursize - 7;
1559 if (host_client->download_file && host_client->download_started && downloadsize > 0)
1561 fs_offset_t downloadstart;
1562 unsigned char data[1400];
1563 downloadstart = FS_Tell(host_client->download_file);
1564 downloadsize = min(downloadsize, (int)sizeof(data));
1565 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1566 // note this sends empty messages if at the end of the file, which is
1567 // necessary to keep the packet loss logic working
1568 // (the last blocks may be lost and need to be re-sent, and that will
1569 // only occur if the client acks the empty end messages, revealing
1570 // a gap in the download progress, causing the last blocks to be
1572 MSG_WriteChar (&msg, svc_downloaddata);
1573 MSG_WriteLong (&msg, downloadstart);
1574 MSG_WriteShort (&msg, downloadsize);
1575 if (downloadsize > 0)
1576 SZ_Write (&msg, data, downloadsize);
1579 // reliable only if none is in progress
1580 if(client->sendsignon != 2 && !client->netconnection->sendMessageLength)
1581 SV_WriteDemoMessage(client, &(client->netconnection->message), false);
1583 SV_WriteDemoMessage(client, &msg, false);
1585 // send the datagram
1586 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->rate_burstsize, client->sendsignon == 2);
1587 if (client->sendsignon == 1 && !client->netconnection->message.cursize)
1588 client->sendsignon = 2; // prevent reliable until client sends prespawn (this is the keepalive phase)
1592 =======================
1593 SV_UpdateToReliableMessages
1594 =======================
1596 static void SV_UpdateToReliableMessages (void)
1598 prvm_prog_t *prog = SVVM_prog;
1606 // check for changes to be sent over the reliable streams
1607 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1609 // update the host_client fields we care about according to the entity fields
1610 host_client->edict = PRVM_EDICT_NUM(i+1);
1613 name = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, netname));
1616 // always point the string back at host_client->name to keep it safe
1617 //strlcpy (host_client->name, name, sizeof (host_client->name));
1618 if (name != host_client->name) // prevent buffer overlap SIGABRT on Mac OSX
1619 dp_strlcpy (host_client->name, name, sizeof (host_client->name));
1622 // DP_SV_CLIENTCOLORS
1623 host_client->colors = (int)PRVM_serveredictfloat(host_client->edict, clientcolors);
1624 if (host_client->old_colors != host_client->colors)
1626 host_client->old_colors = host_client->colors;
1627 // send notification to all clients
1628 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1629 MSG_WriteByte (&sv.reliable_datagram, i);
1630 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1633 // NEXUIZ_PLAYERMODEL
1634 model = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, playermodel));
1637 // always point the string back at host_client->name to keep it safe
1638 //strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1639 if (model != host_client->playermodel) // prevent buffer overlap SIGABRT on Mac OSX
1640 dp_strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1641 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1643 // NEXUIZ_PLAYERSKIN
1644 skin = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, playerskin));
1647 // always point the string back at host_client->name to keep it safe
1648 //strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1649 if (skin != host_client->playerskin) // prevent buffer overlap SIGABRT on Mac OSX
1650 dp_strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1651 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1653 // TODO: add an extension name for this [1/17/2008 Black]
1654 clientcamera = PRVM_serveredictedict(host_client->edict, clientcamera);
1655 if (clientcamera > 0)
1657 int oldclientcamera = host_client->clientcamera;
1658 if (clientcamera >= prog->max_edicts || PRVM_EDICT_NUM(clientcamera)->free)
1659 clientcamera = PRVM_NUM_FOR_EDICT(host_client->edict);
1660 host_client->clientcamera = clientcamera;
1662 if (oldclientcamera != host_client->clientcamera && host_client->netconnection)
1664 MSG_WriteByte(&host_client->netconnection->message, svc_setview);
1665 MSG_WriteShort(&host_client->netconnection->message, host_client->clientcamera);
1670 host_client->frags = (int)PRVM_serveredictfloat(host_client->edict, frags);
1671 if(IS_OLDNEXUIZ_DERIVED(gamemode))
1672 if(!host_client->begun && host_client->netconnection)
1673 host_client->frags = -666;
1674 if (host_client->old_frags != host_client->frags)
1676 host_client->old_frags = host_client->frags;
1677 // send notification to all clients
1678 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1679 MSG_WriteByte (&sv.reliable_datagram, i);
1680 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1684 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1685 if (client->netconnection && (client->begun || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet
1686 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1688 SZ_Clear (&sv.reliable_datagram);
1693 =======================
1694 SV_SendClientMessages
1695 =======================
1697 void SV_SendClientMessages(void)
1699 int i, prepared = false;
1701 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1702 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1704 SV_FlushBroadcastMessages();
1706 // update frags, names, etc
1707 SV_UpdateToReliableMessages();
1709 // build individual updates
1710 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1712 if (!host_client->active)
1714 if (!host_client->netconnection)
1717 if (host_client->netconnection->message.overflowed)
1719 SV_DropClient (true, "Buffer overflow in net message"); // if the message couldn't send, kick off
1726 // only prepare entities once per frame
1727 SV_PrepareEntitiesForSending();
1729 SV_SendClientDatagram(host_client);
1732 // clear muzzle flashes