]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - sv_send.c
b4f7ab638d97853123da3818e345d34d124d1c9a
[xonotic/darkplaces.git] / sv_send.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20
21 #include "quakedef.h"
22 #include "sv_demo.h"
23
24 extern cvar_t sv_airaccel_qw_stretchfactor;
25 extern cvar_t sv_gameplayfix_customstats;
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;
38
39 /*
40 =============================================================================
41
42 EVENT MESSAGES
43
44 =============================================================================
45 */
46
47 /*
48 =================
49 SV_ClientPrint
50
51 Sends text across to be displayed
52 FIXME: make this just a stuffed echo?
53 =================
54 */
55 void SV_ClientPrint(const char *msg)
56 {
57         if (host_client->netconnection)
58         {
59                 MSG_WriteByte(&host_client->netconnection->message, svc_print);
60                 MSG_WriteString(&host_client->netconnection->message, msg);
61         }
62 }
63
64 /*
65 =================
66 SV_ClientPrintf
67
68 Sends text across to be displayed
69 FIXME: make this just a stuffed echo?
70 =================
71 */
72 void SV_ClientPrintf(const char *fmt, ...)
73 {
74         va_list argptr;
75         char msg[MAX_INPUTLINE];
76
77         va_start(argptr,fmt);
78         dpvsnprintf(msg,sizeof(msg),fmt,argptr);
79         va_end(argptr);
80
81         SV_ClientPrint(msg);
82 }
83
84 /*
85 =================
86 SV_BroadcastPrint
87
88 Sends text to all active clients
89 =================
90 */
91 void SV_BroadcastPrint(const char *msg)
92 {
93         int i;
94         client_t *client;
95
96         for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
97         {
98                 if (client->active && client->netconnection)
99                 {
100                         MSG_WriteByte(&client->netconnection->message, svc_print);
101                         MSG_WriteString(&client->netconnection->message, msg);
102                 }
103         }
104
105         if (sv_echobprint.integer && !host_isclient.integer)
106                 Con_Print(msg);
107 }
108
109 /*
110 =================
111 SV_BroadcastPrintf
112
113 Sends text to all active clients
114 =================
115 */
116 void SV_BroadcastPrintf(const char *fmt, ...)
117 {
118         va_list argptr;
119         char msg[MAX_INPUTLINE];
120
121         va_start(argptr,fmt);
122         dpvsnprintf(msg,sizeof(msg),fmt,argptr);
123         va_end(argptr);
124
125         SV_BroadcastPrint(msg);
126 }
127
128 /*
129 =================
130 SV_ClientCommands
131
132 Send text over to the client to be executed
133 =================
134 */
135 void SV_ClientCommands(const char *fmt, ...)
136 {
137         va_list argptr;
138         char string[MAX_INPUTLINE];
139
140         if (!host_client->netconnection)
141                 return;
142
143         va_start(argptr,fmt);
144         dpvsnprintf(string, sizeof(string), fmt, argptr);
145         va_end(argptr);
146
147         MSG_WriteByte(&host_client->netconnection->message, svc_stufftext);
148         MSG_WriteString(&host_client->netconnection->message, string);
149 }
150
151 /*
152 ==================
153 SV_StartParticle
154
155 Make sure the event gets sent to all clients
156 ==================
157 */
158 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
159 {
160         int i;
161
162         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
163                 return;
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();
173 }
174
175 /*
176 ==================
177 SV_StartEffect
178
179 Make sure the event gets sent to all clients
180 ==================
181 */
182 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
183 {
184         if (modelindex >= 256 || startframe >= 256)
185         {
186                 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
187                         return;
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);
196         }
197         else
198         {
199                 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
200                         return;
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);
209         }
210         SV_FlushBroadcastMessages();
211 }
212
213 /*
214 ==================
215 SV_StartSound
216
217 Each entity can have eight independant sound sources, like voice,
218 weapon, feet, etc.
219
220 Channel 0 is an auto-allocate channel, the others override anything
221 already running on that entity/channel pair.
222
223 An attenuation of 0 will play full volume everywhere in the level.
224 Larger attenuations will drop off.  (max 4 attenuation)
225
226 ==================
227 */
228 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int nvolume, float attenuation, qbool reliable, float speed)
229 {
230         prvm_prog_t *prog = SVVM_prog;
231         sizebuf_t *dest;
232         int sound_num, field_mask, i, ent, speed4000;
233
234         dest = (reliable ? &sv.reliable_datagram : &sv.datagram);
235
236         if (nvolume < 0 || nvolume > 255)
237         {
238                 Con_Printf ("SV_StartSound: volume = %i\n", nvolume);
239                 return;
240         }
241
242         if (attenuation < 0 || attenuation > 4)
243         {
244                 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
245                 return;
246         }
247
248         if (!IS_CHAN(channel))
249         {
250                 Con_Printf ("SV_StartSound: channel = %i\n", channel);
251                 return;
252         }
253
254         channel = CHAN_ENGINE2NET(channel);
255
256         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
257                 return;
258
259 // find precache number for sound
260         sound_num = SV_SoundIndex(sample, 1);
261         if (!sound_num)
262                 return;
263
264         ent = PRVM_NUM_FOR_EDICT(entity);
265
266         speed4000 = (int)floor(speed * 4000.0f + 0.5f);
267         field_mask = 0;
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;
278
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)
289         {
290                 MSG_WriteShort (dest, ent);
291                 MSG_WriteChar (dest, channel);
292         }
293         else
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);
297         else
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);
301
302         // TODO do we have to do anything here when dest is &sv.reliable_datagram?
303         if(!reliable)
304                 SV_FlushBroadcastMessages();
305 }
306
307 /*
308 ==================
309 SV_StartPointSound
310
311 Nearly the same logic as SV_StartSound, except an origin
312 instead of an entity is provided and channel is omitted.
313
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.
317
318 ==================
319 */
320 void SV_StartPointSound (vec3_t origin, const char *sample, int nvolume, float attenuation, float speed)
321 {
322         int sound_num, field_mask, i, speed4000;
323
324         if (nvolume < 0 || nvolume > 255)
325         {
326                 Con_Printf ("SV_StartPointSound: volume = %i\n", nvolume);
327                 return;
328         }
329
330         if (attenuation < 0 || attenuation > 4)
331         {
332                 Con_Printf ("SV_StartPointSound: attenuation = %f\n", attenuation);
333                 return;
334         }
335
336         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
337                 return;
338
339         // find precache number for sound
340         sound_num = SV_SoundIndex(sample, 1);
341         if (!sound_num)
342                 return;
343
344         speed4000 = (int)(speed * 40.0f);
345         field_mask = 0;
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;
354
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);
368         else
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();
373 }
374
375 /*
376 ===============================================================================
377
378 FRAME UPDATES
379
380 ===============================================================================
381 */
382
383 /*
384 =============================================================================
385
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
389 crosses a waterline.
390
391 =============================================================================
392 */
393
394 static qbool SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int enumber)
395 {
396         prvm_prog_t *prog = SVVM_prog;
397         int i;
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;
403         float f;
404         prvm_vec_t *v;
405         vec3_t cullmins, cullmaxs;
406         model_t *model;
407
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)
412                 return false;
413
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))
417                 return false;
418
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);
422
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;
428
429         flags = 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;
436
437         v = PRVM_serveredictvector(ent, color);
438         f = v[0]*256;
439         light[0] = (unsigned short)bound(0, f, 65535);
440         f = v[1]*256;
441         light[1] = (unsigned short)bound(0, f, 65535);
442         f = v[2]*256;
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);
448
449         if (gamemode == GAME_TENEBRAE)
450         {
451                 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
452                 if (effects & 16)
453                 {
454                         effects &= ~16;
455                         lightpflags |= PFLAGS_FULLDYNAMIC;
456                 }
457                 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
458                 if (effects & 32)
459                 {
460                         effects &= ~32;
461                         light[0] = (int)(0.2*256);
462                         light[1] = (int)(1.0*256);
463                         light[2] = (int)(0.2*256);
464                         light[3] = 200;
465                         lightpflags |= PFLAGS_FULLDYNAMIC;
466                 }
467         }
468
469         specialvisibilityradius = 0;
470         if (lightpflags & PFLAGS_FULLDYNAMIC)
471                 specialvisibilityradius = max(specialvisibilityradius, light[3]);
472         if (glowsize)
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))
477         {
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);
494         }
495
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))
500                 return false;
501
502         *cs = defaultstate;
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);
507         cs->flags = flags;
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);
522
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))
527         {
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);
531         }
532
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))
537         {
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);
541         }
542
543         cs->modelindex = modelindex;
544
545         cs->alpha = 255;
546         f = (PRVM_serveredictfloat(ent, alpha) * 255.0f);
547         if (f)
548         {
549                 i = (int)f;
550                 cs->alpha = (unsigned char)bound(0, i, 255);
551         }
552         // halflife
553         f = (PRVM_serveredictfloat(ent, renderamt));
554         if (f)
555         {
556                 i = (int)f;
557                 cs->alpha = (unsigned char)bound(0, i, 255);
558         }
559
560         cs->scale = 16;
561         f = (PRVM_serveredictfloat(ent, scale) * 16.0f);
562         if (f)
563         {
564                 i = (int)f;
565                 cs->scale = (unsigned char)bound(0, i, 255);
566         }
567
568         cs->glowcolor = 254;
569         f = PRVM_serveredictfloat(ent, glow_color);
570         if (f)
571                 cs->glowcolor = (int)f;
572
573         if (PRVM_serveredictfloat(ent, fullbright))
574                 cs->effects |= EF_FULLBRIGHT;
575
576         f = PRVM_serveredictfloat(ent, modelflags);
577         if (f)
578                 cs->effects |= ((unsigned int)f & 0xff) << 24;
579
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
588
589         if (PRVM_serveredictfloat(ent, sendcomplexanimation))
590         {
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
607         }
608
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;
615
616         cs->specialvisibilityradius = specialvisibilityradius;
617
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))
622         {
623                 float scale = cs->scale * (1.0f / 16.0f);
624                 if (cs->angles[0] || cs->angles[2]) // pitch and roll
625                 {
626                         VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
627                         VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
628                 }
629                 else if (cs->angles[1] || ((effects | model->effects) & EF_ROTATE))
630                 {
631                         VectorMA(cs->origin, scale, model->yawmins, cullmins);
632                         VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
633                 }
634                 else
635                 {
636                         VectorMA(cs->origin, scale, model->normalmins, cullmins);
637                         VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
638                 }
639         }
640         else
641         {
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);
645         }
646         if (specialvisibilityradius)
647         {
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);
654         }
655
656         // calculate center of bbox for network prioritization purposes
657         VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
658
659         // if culling box has moved, update pvs cluster links
660         if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
661         {
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)
670                 {
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;
674                 }
675         }
676
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)
680         if (sendentity)
681         {
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)))
686                 {
687                         if (sv.csqcentityversion[enumber] != version)
688                                 sendflags = 0xFFFFFF;
689                         sv.csqcentityversion[enumber] = version;
690                 }
691                 // move sendflags into the per-client sendflags
692                 if (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;
697         }
698
699         return true;
700 }
701
702 static void SV_PrepareEntitiesForSending(void)
703 {
704         prvm_prog_t *prog = SVVM_prog;
705         int e;
706         prvm_edict_t *ent;
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))
712         {
713                 if (!ent->free && SV_PrepareEntityForSending(ent, sv.sendentities + sv.numsendentities, e))
714                 {
715                         sv.sendentitiesindex[e] = sv.sendentities + sv.numsendentities;
716                         sv.numsendentities++;
717                 }
718         }
719 }
720
721 #define MAX_LINEOFSIGHTTRACES 64
722
723 qbool SV_CanSeeBox(int numtraces, vec_t eyejitter, vec_t enlarge, vec_t entboxexpand, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
724 {
725         prvm_prog_t *prog = SVVM_prog;
726         float pitchsign;
727         float alpha;
728         float starttransformed[3], endtransformed[3];
729         float boxminstransformed[3], boxmaxstransformed[3];
730         float localboxcenter[3], localboxextents[3], localboxmins[3], localboxmaxs[3];
731         int blocked = 0;
732         int traceindex;
733         int originalnumtouchedicts;
734         int numtouchedicts = 0;
735         int touchindex;
736         matrix4x4_t matrix, imatrix;
737         model_t *model;
738         prvm_edict_t *touch;
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];
744
745         numtraces = min(numtraces, MAX_LINEOFSIGHTTRACES);
746
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;
761
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]));
765
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++)
770         {
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]);
777         }
778
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)
783         {
784                 // this never happens
785                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
786                 numtouchedicts = MAX_EDICTS;
787         }
788         // iterate the entities found in the sweep box and filter them
789         originalnumtouchedicts = numtouchedicts;
790         numtouchedicts = 0;
791         for (touchindex = 0;touchindex < originalnumtouchedicts;touchindex++)
792         {
793                 touch = touchedicts[touchindex];
794                 if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
795                         continue;
796                 model = SV_GetModelFromEdict(touch);
797                 if (!model || !model->brush.TraceLineOfSight)
798                         continue;
799                 // skip obviously transparent entities
800                 alpha = PRVM_serveredictfloat(touch, alpha);
801                 if (alpha && alpha < 1)
802                         continue;
803                 if ((int)PRVM_serveredictfloat(touch, effects) & EF_ADDITIVE)
804                         continue;
805                 touchedicts[numtouchedicts++] = touch;
806         }
807
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)
811
812         for (traceindex = 0;traceindex < numtraces;traceindex++)
813         {
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))
818                                 continue;
819                 for (touchindex = 0;touchindex < numtouchedicts;touchindex++)
820                 {
821                         touch = touchedicts[touchindex];
822                         model = SV_GetModelFromEdict(touch);
823                         if(model && model->brush.TraceLineOfSight)
824                         {
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))
846                                 {
847                                         blocked++;
848                                         break;
849                                 }
850                         }
851                 }
852                 // check if the ray was blocked
853                 if (touchindex < numtouchedicts)
854                         continue;
855                 // return if the ray was not blocked
856                 return true;
857         }
858
859         // no rays survived
860         return false;
861 }
862
863 void SV_MarkWriteEntityStateToClient(entity_state_t *s, client_t *client)
864 {
865         prvm_prog_t *prog = SVVM_prog;
866         int isbmodel;
867         model_t *model;
868         prvm_edict_t *ed;
869         if (sv.sententitiesconsideration[s->number] == sv.sententitiesmark)
870                 return;
871         sv.sententitiesconsideration[s->number] = sv.sententitiesmark;
872         sv.writeentitiestoclient_stats_totalentities++;
873
874         if (s->customizeentityforclient)
875         {
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))
881                         return;
882         }
883
884         // never reject player
885         if (s->number != sv.writeentitiestoclient_cliententitynumber)
886         {
887                 // check various rejection conditions
888                 if (s->nodrawtoclient == sv.writeentitiestoclient_cliententitynumber)
889                         return;
890                 if (s->drawonlytoclient && s->drawonlytoclient != sv.writeentitiestoclient_cliententitynumber)
891                         return;
892                 if (s->effects & EF_NODRAW)
893                         return;
894                 // LadyHavoc: only send entities with a model or important effects
895                 if (!s->modelindex && s->specialvisibilityradius == 0)
896                         return;
897
898                 isbmodel = (model = SV_GetModelByIndex(s->modelindex)) != NULL && model->name[0] == '*';
899                 // viewmodels don't have visibility checking
900                 if (s->viewmodelforclient)
901                 {
902                         if (s->viewmodelforclient != sv.writeentitiestoclient_cliententitynumber)
903                                 return;
904                 }
905                 else if (s->tagentity)
906                 {
907                         // tag attached entities simply check their parent
908                         if (!sv.sendentitiesindex[s->tagentity])
909                                 return;
910                         SV_MarkWriteEntityStateToClient(sv.sendentitiesindex[s->tagentity], client);
911                         if (sv.sententities[s->tagentity] != sv.sententitiesmark)
912                                 return;
913                 }
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))
918                 {
919                         // entity has survived every check so far, check if visible
920                         ed = PRVM_EDICT_NUM(s->number);
921
922                         // if not touching a visible leaf
923                         if (sv_cullentities_pvs.integer && !r_novis.integer && !r_trippy.integer && sv.writeentitiestoclient_pvsbytes)
924                         {
925                                 if (ed->priv.server->pvs_numclusters < 0)
926                                 {
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))
929                                         {
930                                                 sv.writeentitiestoclient_stats_culled_pvs++;
931                                                 return;
932                                         }
933                                 }
934                                 else
935                                 {
936                                         int i;
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]))
940                                                         break;
941                                         if (i == ed->priv.server->pvs_numclusters)
942                                         {
943                                                 sv.writeentitiestoclient_stats_culled_pvs++;
944                                                 return;
945                                         }
946                                 }
947                         }
948
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))
951                         {
952                                 int samples =
953                                         s->number <= svs.maxclients
954                                                 ? sv_cullentities_trace_samples_players.integer
955                                                 :
956                                         s->specialvisibilityradius
957                                                 ? sv_cullentities_trace_samples_extra.integer
958                                                 : sv_cullentities_trace_samples.integer;
959                                 float enlarge = sv_cullentities_trace_enlarge.value;
960
961                                 if(samples > 0)
962                                 {
963                                         int eyeindex;
964                                         for (eyeindex = 0;eyeindex < sv.writeentitiestoclient_numeyes;eyeindex++)
965                                                 if(SV_CanSeeBox(samples, sv_cullentities_trace_eyejitter.value, enlarge, sv_cullentities_trace_expand.value, sv.writeentitiestoclient_eyes[eyeindex], ed->priv.server->cullmins, ed->priv.server->cullmaxs))
966                                                         break;
967                                         if(eyeindex < sv.writeentitiestoclient_numeyes)
968                                                 svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number] =
969                                                         host.realtime + (
970                                                                 s->number <= svs.maxclients
971                                                                         ? sv_cullentities_trace_delay_players.value
972                                                                         : sv_cullentities_trace_delay.value
973                                                         );
974                                         else if ((float)host.realtime > svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number])
975                                         {
976                                                 sv.writeentitiestoclient_stats_culled_trace++;
977                                                 return;
978                                         }
979                                 }
980                         }
981                 }
982         }
983
984         // this just marks it for sending
985         // FIXME: it would be more efficient to send here, but the entity
986         // compressor isn't that flexible
987         sv.writeentitiestoclient_stats_visibleentities++;
988         sv.sententities[s->number] = sv.sententitiesmark;
989 }
990
991 #if MAX_LEVELNETWORKEYES > 0
992 #define MAX_EYE_RECURSION 1 // increase if recursion gets supported by portals
993 void SV_AddCameraEyes(void)
994 {
995         prvm_prog_t *prog = SVVM_prog;
996         int e, i, j, k;
997         prvm_edict_t *ed;
998         static int cameras[MAX_LEVELNETWORKEYES];
999         static vec3_t camera_origins[MAX_LEVELNETWORKEYES];
1000         static int eye_levels[MAX_CLIENTNETWORKEYES];
1001         int n_cameras = 0;
1002         vec3_t mi, ma;
1003
1004         for(i = 0; i < sv.writeentitiestoclient_numeyes; ++i)
1005                 eye_levels[i] = 0;
1006
1007         // check line of sight to portal entities and add them to PVS
1008         for (e = 1, ed = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ed = PRVM_NEXT_EDICT(ed))
1009         {
1010                 if (!ed->free)
1011                 {
1012                         if(PRVM_serveredictfunction(ed, camera_transform))
1013                         {
1014                                 PRVM_serverglobalfloat(time) = sv.time;
1015                                 PRVM_serverglobaledict(self) = e;
1016                                 PRVM_serverglobaledict(other) = sv.writeentitiestoclient_cliententitynumber;
1017                                 VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_serverglobalvector(trace_endpos));
1018                                 VectorCopy(sv.writeentitiestoclient_eyes[0], PRVM_G_VECTOR(OFS_PARM0));
1019                                 VectorClear(PRVM_G_VECTOR(OFS_PARM1));
1020                                 prog->ExecuteProgram(prog, PRVM_serveredictfunction(ed, camera_transform), "QC function e.camera_transform is missing");
1021                                 if(!VectorCompare(PRVM_serverglobalvector(trace_endpos), sv.writeentitiestoclient_eyes[0]))
1022                                 {
1023                                         VectorCopy(PRVM_serverglobalvector(trace_endpos), camera_origins[n_cameras]);
1024                                         cameras[n_cameras] = e;
1025                                         ++n_cameras;
1026                                         if(n_cameras >= MAX_LEVELNETWORKEYES)
1027                                                 break;
1028                                 }
1029                         }
1030                 }
1031         }
1032
1033         if(!n_cameras)
1034                 return;
1035
1036         // i is loop counter, is reset to 0 when an eye got added
1037         // j is camera index to check
1038         for(i = 0, j = 0; sv.writeentitiestoclient_numeyes < MAX_CLIENTNETWORKEYES && i < n_cameras; ++i, ++j, j %= n_cameras)
1039         {
1040                 if(!cameras[j])
1041                         continue;
1042                 ed = PRVM_EDICT_NUM(cameras[j]);
1043                 VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, mins), mi);
1044                 VectorAdd(PRVM_serveredictvector(ed, origin), PRVM_serveredictvector(ed, maxs), ma);
1045                 for(k = 0; k < sv.writeentitiestoclient_numeyes; ++k)
1046                 if(eye_levels[k] <= MAX_EYE_RECURSION)
1047                 {
1048                         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))
1049                                 svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[cameras[j]] = host.realtime + sv_cullentities_trace_delay.value;
1050
1051                         // bones_was_here: this use of visibletime doesn't conflict because sv_cullentities_trace doesn't consider portal entities
1052                         // the explicit cast prevents float precision differences that cause the condition to fail
1053                         if ((float)host.realtime <= svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[cameras[j]])
1054                         {
1055                                 eye_levels[sv.writeentitiestoclient_numeyes] = eye_levels[k] + 1;
1056                                 VectorCopy(camera_origins[j], sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
1057                                 // 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);
1058                                 sv.writeentitiestoclient_numeyes++;
1059                                 cameras[j] = 0;
1060                                 i = 0;
1061                                 break;
1062                         }
1063                 }
1064         }
1065 }
1066 #else
1067 void SV_AddCameraEyes(void)
1068 {
1069 }
1070 #endif
1071
1072 /*
1073 =============
1074 SV_CleanupEnts
1075
1076 =============
1077 */
1078 static void SV_CleanupEnts (void)
1079 {
1080         prvm_prog_t *prog = SVVM_prog;
1081         int             e;
1082         prvm_edict_t    *ent;
1083
1084         ent = PRVM_NEXT_EDICT(prog->edicts);
1085         for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1086                 PRVM_serveredictfloat(ent, effects) = (int)PRVM_serveredictfloat(ent, effects) & ~EF_MUZZLEFLASH;
1087 }
1088
1089 /*
1090 ==================
1091 SV_WriteClientdataToMessage
1092
1093 ==================
1094 */
1095 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1096 {
1097         prvm_prog_t *prog = SVVM_prog;
1098         int             bits;
1099         int             i;
1100         prvm_edict_t    *other;
1101         int             items;
1102         vec3_t  punchvector;
1103         int             viewzoom;
1104         const char *s;
1105         float   *statsf = (float *)stats;
1106         float gravity;
1107
1108 //
1109 // send a damage message
1110 //
1111         if (PRVM_serveredictfloat(ent, dmg_take) || PRVM_serveredictfloat(ent, dmg_save))
1112         {
1113                 other = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, dmg_inflictor));
1114                 MSG_WriteByte (msg, svc_damage);
1115                 MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_save));
1116                 MSG_WriteByte (msg, (int)PRVM_serveredictfloat(ent, dmg_take));
1117                 for (i=0 ; i<3 ; i++)
1118                         MSG_WriteCoord (msg, PRVM_serveredictvector(other, origin)[i] + 0.5*(PRVM_serveredictvector(other, mins)[i] + PRVM_serveredictvector(other, maxs)[i]), sv.protocol);
1119
1120                 PRVM_serveredictfloat(ent, dmg_take) = 0;
1121                 PRVM_serveredictfloat(ent, dmg_save) = 0;
1122         }
1123
1124 //
1125 // send the current viewpos offset from the view entity
1126 //
1127         SV_SetIdealPitch ();            // how much to look up / down ideally
1128
1129 // a fixangle might get lost in a dropped packet.  Oh well.
1130         if(PRVM_serveredictfloat(ent, fixangle))
1131         {
1132                 // angle fixing was requested by global thinking code...
1133                 // so store the current angles for later use
1134                 VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles);
1135                 host_client->fixangle_angles_set = true;
1136
1137                 // and clear fixangle for the next frame
1138                 PRVM_serveredictfloat(ent, fixangle) = 0;
1139         }
1140
1141         if (host_client->fixangle_angles_set)
1142         {
1143                 MSG_WriteByte (msg, svc_setangle);
1144                 for (i=0 ; i < 3 ; i++)
1145                         MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
1146                 host_client->fixangle_angles_set = false;
1147         }
1148
1149         // the runes are in serverflags, pack them into the items value, also pack
1150         // in the items2 value for mission pack huds
1151         // (used only in the mission packs, which do not use serverflags)
1152         items = (int)PRVM_serveredictfloat(ent, items) | ((int)PRVM_serveredictfloat(ent, items2) << 23) | ((int)PRVM_serverglobalfloat(serverflags) << 28);
1153
1154         VectorCopy(PRVM_serveredictvector(ent, punchvector), punchvector);
1155
1156         // cache weapon model name and index in client struct to save time
1157         // (this search can be almost 1% of cpu time!)
1158         s = PRVM_GetString(prog, PRVM_serveredictstring(ent, weaponmodel));
1159         if (strcmp(s, client->weaponmodel))
1160         {
1161                 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1162                 client->weaponmodelindex = SV_ModelIndex(s, 1);
1163         }
1164
1165         viewzoom = (int)(PRVM_serveredictfloat(ent, viewzoom) * 255.0f);
1166         if (viewzoom == 0)
1167                 viewzoom = 255;
1168
1169         bits = 0;
1170
1171         if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
1172                 bits |= SU_ONGROUND;
1173         if (PRVM_serveredictfloat(ent, waterlevel) >= 2)
1174                 bits |= SU_INWATER;
1175         if (PRVM_serveredictfloat(ent, idealpitch))
1176                 bits |= SU_IDEALPITCH;
1177
1178         for (i=0 ; i<3 ; i++)
1179         {
1180                 if (PRVM_serveredictvector(ent, punchangle)[i])
1181                         bits |= (SU_PUNCH1<<i);
1182                 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)
1183                         if (punchvector[i])
1184                                 bits |= (SU_PUNCHVEC1<<i);
1185                 if (PRVM_serveredictvector(ent, velocity)[i])
1186                         bits |= (SU_VELOCITY1<<i);
1187         }
1188
1189         gravity = PRVM_serveredictfloat(ent, gravity);if (!gravity) gravity = 1.0f;
1190
1191         memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1192         stats[STAT_VIEWHEIGHT] = (int)PRVM_serveredictvector(ent, view_ofs)[2];
1193         stats[STAT_ITEMS] = items;
1194         stats[STAT_WEAPONFRAME] = (int)PRVM_serveredictfloat(ent, weaponframe);
1195         stats[STAT_ARMOR] = (int)PRVM_serveredictfloat(ent, armorvalue);
1196         stats[STAT_WEAPON] = client->weaponmodelindex;
1197         stats[STAT_HEALTH] = (int)PRVM_serveredictfloat(ent, health);
1198         stats[STAT_AMMO] = (int)PRVM_serveredictfloat(ent, currentammo);
1199         stats[STAT_SHELLS] = (int)PRVM_serveredictfloat(ent, ammo_shells);
1200         stats[STAT_NAILS] = (int)PRVM_serveredictfloat(ent, ammo_nails);
1201         stats[STAT_ROCKETS] = (int)PRVM_serveredictfloat(ent, ammo_rockets);
1202         stats[STAT_CELLS] = (int)PRVM_serveredictfloat(ent, ammo_cells);
1203         stats[STAT_ACTIVEWEAPON] = (int)PRVM_serveredictfloat(ent, weapon);
1204         stats[STAT_VIEWZOOM] = viewzoom;
1205         stats[STAT_TOTALSECRETS] = (int)PRVM_serverglobalfloat(total_secrets);
1206         stats[STAT_TOTALMONSTERS] = (int)PRVM_serverglobalfloat(total_monsters);
1207         // the QC bumps these itself by sending svc_'s, so we have to keep them
1208         // zero or they'll be corrected by the engine
1209         //stats[STAT_SECRETS] = PRVM_serverglobalfloat(found_secrets);
1210         //stats[STAT_MONSTERS] = PRVM_serverglobalfloat(killed_monsters);
1211
1212         if(!sv_gameplayfix_customstats.integer)
1213         {
1214                 statsf[STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR] = sv_airaccel_qw_stretchfactor.value;
1215                 statsf[STAT_MOVEVARS_AIRCONTROL_PENALTY] = sv_aircontrol_penalty.value;
1216                 statsf[STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW] = sv_airspeedlimit_nonqw.value;               
1217                 statsf[STAT_MOVEVARS_AIRSTRAFEACCEL_QW] = sv_airstrafeaccel_qw.value;
1218                 statsf[STAT_MOVEVARS_AIRCONTROL_POWER] = sv_aircontrol_power.value;
1219                 // movement settings for prediction
1220                 // note: these are not sent in protocols with lower MAX_CL_STATS limits
1221                 stats[STAT_MOVEFLAGS] = MOVEFLAG_VALID
1222                         | (sv_gameplayfix_q2airaccelerate.integer ? MOVEFLAG_Q2AIRACCELERATE : 0)
1223                         | (sv_gameplayfix_nogravityonground.integer ? MOVEFLAG_NOGRAVITYONGROUND : 0)
1224                         | (sv_gameplayfix_gravityunaffectedbyticrate.integer ? MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE : 0)
1225                 ;
1226                 statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL] = sv_warsowbunny_airforwardaccel.value;
1227                 statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL] = sv_warsowbunny_accel.value;
1228                 statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED] = sv_warsowbunny_topspeed.value;
1229                 statsf[STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL] = sv_warsowbunny_turnaccel.value;
1230                 statsf[STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO] = sv_warsowbunny_backtosideratio.value;
1231                 statsf[STAT_MOVEVARS_AIRSTOPACCELERATE] = sv_airstopaccelerate.value;
1232                 statsf[STAT_MOVEVARS_AIRSTRAFEACCELERATE] = sv_airstrafeaccelerate.value;
1233                 statsf[STAT_MOVEVARS_MAXAIRSTRAFESPEED] = sv_maxairstrafespeed.value;
1234                 statsf[STAT_MOVEVARS_AIRCONTROL] = sv_aircontrol.value;
1235                 statsf[STAT_FRAGLIMIT] = fraglimit.value;
1236                 statsf[STAT_TIMELIMIT] = timelimit.value;
1237                 statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value;     
1238                 statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value;
1239                 statsf[STAT_MOVEVARS_TICRATE] = sys_ticrate.value;
1240                 statsf[STAT_MOVEVARS_TIMESCALE] = host_timescale.value;
1241                 statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
1242                 statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
1243                 statsf[STAT_MOVEVARS_MAXSPEED] = sv_maxspeed.value;
1244                 statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_maxspeed.value; // FIXME: QW has a separate cvar for this
1245                 statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
1246                 statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value;
1247                 statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value;
1248                 statsf[STAT_MOVEVARS_ENTGRAVITY] = gravity;
1249                 statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value;
1250                 statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
1251                 statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value;
1252                 statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value;
1253                 statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value;
1254                 statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
1255         }
1256
1257         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)
1258         {
1259                 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1260                 bits |= SU_ITEMS;
1261                 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1262                 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1263                 bits |= SU_WEAPON;
1264                 // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
1265                 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1266                         if (viewzoom != 255)
1267                                 bits |= SU_VIEWZOOM;
1268         }
1269
1270         if (bits >= 65536)
1271                 bits |= SU_EXTEND1;
1272         if (bits >= 16777216)
1273                 bits |= SU_EXTEND2;
1274
1275         // send the data
1276         MSG_WriteByte (msg, svc_clientdata);
1277         MSG_WriteShort (msg, bits);
1278         if (bits & SU_EXTEND1)
1279                 MSG_WriteByte(msg, bits >> 16);
1280         if (bits & SU_EXTEND2)
1281                 MSG_WriteByte(msg, bits >> 24);
1282
1283         if (bits & SU_VIEWHEIGHT)
1284                 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1285
1286         if (bits & SU_IDEALPITCH)
1287                 MSG_WriteChar (msg, (int)PRVM_serveredictfloat(ent, idealpitch));
1288
1289         for (i=0 ; i<3 ; i++)
1290         {
1291                 if (bits & (SU_PUNCH1<<i))
1292                 {
1293                         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)
1294                                 MSG_WriteChar(msg, (int)PRVM_serveredictvector(ent, punchangle)[i]);
1295                         else
1296                                 MSG_WriteAngle16i(msg, PRVM_serveredictvector(ent, punchangle)[i]);
1297                 }
1298                 if (bits & (SU_PUNCHVEC1<<i))
1299                 {
1300                         if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1301                                 MSG_WriteCoord16i(msg, punchvector[i]);
1302                         else
1303                                 MSG_WriteCoord32f(msg, punchvector[i]);
1304                 }
1305                 if (bits & (SU_VELOCITY1<<i))
1306                 {
1307                         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)
1308                                 MSG_WriteChar(msg, (int)(PRVM_serveredictvector(ent, velocity)[i] * (1.0f / 16.0f)));
1309                         else
1310                                 MSG_WriteCoord32f(msg, PRVM_serveredictvector(ent, velocity)[i]);
1311                 }
1312         }
1313
1314         if (bits & SU_ITEMS)
1315                 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1316
1317         if (sv.protocol == PROTOCOL_DARKPLACES5)
1318         {
1319                 if (bits & SU_WEAPONFRAME)
1320                         MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1321                 if (bits & SU_ARMOR)
1322                         MSG_WriteShort (msg, stats[STAT_ARMOR]);
1323                 if (bits & SU_WEAPON)
1324                         MSG_WriteShort (msg, stats[STAT_WEAPON]);
1325                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1326                 MSG_WriteShort (msg, stats[STAT_AMMO]);
1327                 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1328                 MSG_WriteShort (msg, stats[STAT_NAILS]);
1329                 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1330                 MSG_WriteShort (msg, stats[STAT_CELLS]);
1331                 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1332                 if (bits & SU_VIEWZOOM)
1333                         MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1334         }
1335         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)
1336         {
1337                 if (bits & SU_WEAPONFRAME)
1338                         MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1339                 if (bits & SU_ARMOR)
1340                         MSG_WriteByte (msg, stats[STAT_ARMOR]);
1341                 if (bits & SU_WEAPON)
1342                 {
1343                         if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1344                                 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1345                         else
1346                                 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1347                 }
1348                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1349                 MSG_WriteByte (msg, stats[STAT_AMMO]);
1350                 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1351                 MSG_WriteByte (msg, stats[STAT_NAILS]);
1352                 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1353                 MSG_WriteByte (msg, stats[STAT_CELLS]);
1354                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_QUOTH || IS_OLDNEXUIZ_DERIVED(gamemode))
1355                 {
1356                         for (i = 0;i < 32;i++)
1357                                 if (stats[STAT_ACTIVEWEAPON] & (1<<i))
1358                                         break;
1359                         MSG_WriteByte (msg, i);
1360                 }
1361                 else
1362                         MSG_WriteByte (msg, stats[STAT_ACTIVEWEAPON]);
1363                 if (bits & SU_VIEWZOOM)
1364                 {
1365                         if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1366                                 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1367                         else
1368                                 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1369                 }
1370         }
1371 }
1372
1373 void SV_FlushBroadcastMessages(void)
1374 {
1375         int i;
1376         client_t *client;
1377         if (sv.datagram.cursize <= 0)
1378                 return;
1379         for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1380         {
1381                 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])))
1382                         continue;
1383                 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1384                 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1385         }
1386         SZ_Clear(&sv.datagram);
1387 }
1388
1389 static void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg, int maxsize, int maxsize2)
1390 {
1391         // scan the splitpoints to find out how many we can fit in
1392         int numsegments, j, split;
1393         if (!client->unreliablemsg_splitpoints)
1394                 return;
1395         // always accept the first one if it's within 1024 bytes, this ensures
1396         // that very big datagrams which are over the rate limit still get
1397         // through, just to keep it working
1398         for (numsegments = 1;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1399                 if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > maxsize)
1400                         break;
1401         // the first segment gets an exemption from the rate limiting, otherwise
1402         // it could get dropped consistently due to a low rate limit
1403         if (numsegments == 1)
1404                 maxsize = maxsize2;
1405         // some will fit, so add the ones that will fit
1406         split = client->unreliablemsg_splitpoint[numsegments-1];
1407         // note this discards ones that were accepted by the segments scan but
1408         // can not fit, such as a really huge first one that will never ever
1409         // fit in a packet...
1410         if (msg->cursize + split <= maxsize)
1411                 SZ_Write(msg, client->unreliablemsg.data, split);
1412         // remove the part we sent, keeping any remaining data
1413         client->unreliablemsg.cursize -= split;
1414         if (client->unreliablemsg.cursize > 0)
1415                 memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
1416         // adjust remaining splitpoints
1417         client->unreliablemsg_splitpoints -= numsegments;
1418         for (j = 0;j < client->unreliablemsg_splitpoints;j++)
1419                 client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
1420 }
1421
1422 /*
1423 =======================
1424 SV_SendClientDatagram
1425 =======================
1426 */
1427 static void SV_SendClientDatagram (client_t *client)
1428 {
1429         int clientrate, maxrate, maxsize, maxsize2, downloadsize;
1430         sizebuf_t msg;
1431         int stats[MAX_CL_STATS];
1432         static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE];
1433         double timedelta;
1434
1435         // obey rate limit by limiting packet frequency if the packet size
1436         // limiting fails
1437         // (usually this is caused by reliable messages)
1438         if (!NetConn_CanSend(client->netconnection))
1439                 return;
1440
1441         // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1442         maxrate = max(NET_MINRATE, sv_maxrate.integer);
1443         if (sv_maxrate.integer != maxrate)
1444                 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1445
1446         // clientrate determines the 'cleartime' of a packet
1447         // (how long to wait before sending another, based on this packet's size)
1448         clientrate = bound(NET_MINRATE, client->rate, maxrate);
1449
1450         switch (sv.protocol)
1451         {
1452         case PROTOCOL_QUAKE:
1453         case PROTOCOL_QUAKEDP:
1454         case PROTOCOL_NEHAHRAMOVIE:
1455         case PROTOCOL_NEHAHRABJP:
1456         case PROTOCOL_NEHAHRABJP2:
1457         case PROTOCOL_NEHAHRABJP3:
1458         case PROTOCOL_QUAKEWORLD:
1459                 // no packet size limit support on Quake protocols because it just
1460                 // causes missing entities/effects
1461                 // packets are simply sent less often to obey the rate limit
1462                 maxsize = 1024;
1463                 maxsize2 = 1024;
1464                 break;
1465         case PROTOCOL_DARKPLACES1:
1466         case PROTOCOL_DARKPLACES2:
1467         case PROTOCOL_DARKPLACES3:
1468         case PROTOCOL_DARKPLACES4:
1469                 // no packet size limit support on DP1-4 protocols because they kick
1470                 // the client off if they overflow, and miss effects
1471                 // packets are simply sent less often to obey the rate limit
1472                 maxsize = sizeof(sv_sendclientdatagram_buf);
1473                 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1474                 break;
1475         default:
1476                 // DP5 and later protocols support packet size limiting which is a
1477                 // better method than limiting packet frequency as QW does
1478                 //
1479                 // at very low rates (or very small sys_ticrate) the packet size is
1480                 // not reduced below 128, but packets may be sent less often
1481
1482                 // how long are bursts?
1483                 timedelta = host_client->rate_burstsize / (double)client->rate;
1484
1485                 // how much of the burst do we keep reserved?
1486                 timedelta *= 1 - net_burstreserve.value;
1487
1488                 // only try to use excess time
1489                 timedelta = bound(0, host.realtime - host_client->netconnection->cleartime, timedelta);
1490
1491                 // but we know next packet will be in sys_ticrate, so we can use up THAT bandwidth
1492                 timedelta += sys_ticrate.value;
1493
1494                 // note: packet overhead (not counted in maxsize) is 28 bytes
1495                 maxsize = (int)(clientrate * timedelta) - 28;
1496
1497                 // put it in sound bounds
1498                 maxsize = bound(128, maxsize, 1400);
1499                 maxsize2 = 1400;
1500
1501                 // csqc entities can easily exceed 128 bytes, so disable throttling in
1502                 // mods that use csqc (they are likely to use less bandwidth anyway)
1503                 if((net_usesizelimit.integer == 1) ? (sv.csqc_progsize > 0) : (net_usesizelimit.integer < 1))
1504                         maxsize = maxsize2;
1505
1506                 break;
1507         }
1508
1509         if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !host_limitlocal.integer)
1510         {
1511                 // for good singleplayer, send huge packets
1512                 maxsize = sizeof(sv_sendclientdatagram_buf);
1513                 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1514                 // never limit frequency in singleplayer
1515                 clientrate = 1000000000;
1516         }
1517
1518         // while downloading, limit entity updates to half the packet
1519         // (any leftover space will be used for downloading)
1520         if (host_client->download_file)
1521                 maxsize /= 2;
1522
1523         msg.data = sv_sendclientdatagram_buf;
1524         msg.maxsize = sizeof(sv_sendclientdatagram_buf);
1525         msg.cursize = 0;
1526         msg.allowoverflow = false;
1527
1528         if (host_client->begun)
1529         {
1530                 // the player is in the game
1531                 MSG_WriteByte (&msg, svc_time);
1532                 MSG_WriteFloat (&msg, sv.time);
1533
1534                 // add the client specific data to the datagram
1535                 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1536                 // now update the stats[] array using any registered custom fields
1537                 VM_SV_UpdateCustomStats(client, client->edict, &msg, stats);
1538                 // set host_client->statsdeltabits
1539                 Protocol_UpdateClientStats (stats);
1540
1541                 // add as many queued unreliable messages (effects) as we can fit
1542                 // limit effects to half of the remaining space
1543                 if (client->unreliablemsg.cursize)
1544                         SV_WriteUnreliableMessages (client, &msg, maxsize/2, maxsize2);
1545
1546                 // now write as many entities as we can fit, and also sends stats
1547                 SV_WriteEntitiesToClient (client, client->edict, &msg, maxsize);
1548         }
1549         else if (host.realtime > client->keepalivetime)
1550         {
1551                 // the player isn't totally in the game yet
1552                 // send small keepalive messages if too much time has passed
1553                 // (may also be sending downloads)
1554                 client->keepalivetime = host.realtime + 5;
1555                 MSG_WriteChar (&msg, svc_nop);
1556         }
1557
1558         // if a download is active, see if there is room to fit some download data
1559         // in this packet
1560         downloadsize = min(maxsize*2,maxsize2) - msg.cursize - 7;
1561         if (host_client->download_file && host_client->download_started && downloadsize > 0)
1562         {
1563                 fs_offset_t downloadstart;
1564                 unsigned char data[1400];
1565                 downloadstart = FS_Tell(host_client->download_file);
1566                 downloadsize = min(downloadsize, (int)sizeof(data));
1567                 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1568                 // note this sends empty messages if at the end of the file, which is
1569                 // necessary to keep the packet loss logic working
1570                 // (the last blocks may be lost and need to be re-sent, and that will
1571                 //  only occur if the client acks the empty end messages, revealing
1572                 //  a gap in the download progress, causing the last blocks to be
1573                 //  sent again)
1574                 MSG_WriteChar (&msg, svc_downloaddata);
1575                 MSG_WriteLong (&msg, downloadstart);
1576                 MSG_WriteShort (&msg, downloadsize);
1577                 if (downloadsize > 0)
1578                         SZ_Write (&msg, data, downloadsize);
1579         }
1580
1581         // reliable only if none is in progress
1582         if(client->sendsignon != 2 && !client->netconnection->sendMessageLength)
1583                 SV_WriteDemoMessage(client, &(client->netconnection->message), false);
1584         // unreliable
1585         SV_WriteDemoMessage(client, &msg, false);
1586
1587 // send the datagram
1588         NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->rate_burstsize, client->sendsignon == 2);
1589         if (client->sendsignon == 1 && !client->netconnection->message.cursize)
1590                 client->sendsignon = 2; // prevent reliable until client sends prespawn (this is the keepalive phase)
1591 }
1592
1593 /*
1594 =======================
1595 SV_UpdateToReliableMessages
1596 =======================
1597 */
1598 static void SV_UpdateToReliableMessages (void)
1599 {
1600         prvm_prog_t *prog = SVVM_prog;
1601         int i, j;
1602         client_t *client;
1603         const char *name;
1604         const char *model;
1605         const char *skin;
1606         int clientcamera;
1607
1608 // check for changes to be sent over the reliable streams
1609         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1610         {
1611                 // update the host_client fields we care about according to the entity fields
1612                 host_client->edict = PRVM_EDICT_NUM(i+1);
1613
1614                 // DP_SV_CLIENTNAME
1615                 name = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, netname));
1616                 if (name == NULL)
1617                         name = "";
1618                 // always point the string back at host_client->name to keep it safe
1619                 //strlcpy (host_client->name, name, sizeof (host_client->name));
1620                 if (name != host_client->name) // prevent buffer overlap SIGABRT on Mac OSX
1621                         strlcpy (host_client->name, name, sizeof (host_client->name));
1622                 SV_Name(i);
1623
1624                 // DP_SV_CLIENTCOLORS
1625                 host_client->colors = (int)PRVM_serveredictfloat(host_client->edict, clientcolors);
1626                 if (host_client->old_colors != host_client->colors)
1627                 {
1628                         host_client->old_colors = host_client->colors;
1629                         // send notification to all clients
1630                         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1631                         MSG_WriteByte (&sv.reliable_datagram, i);
1632                         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1633                 }
1634
1635                 // NEXUIZ_PLAYERMODEL
1636                 model = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, playermodel));
1637                 if (model == NULL)
1638                         model = "";
1639                 // always point the string back at host_client->name to keep it safe
1640                 //strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1641                 if (model != host_client->playermodel) // prevent buffer overlap SIGABRT on Mac OSX
1642                         strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1643                 PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
1644
1645                 // NEXUIZ_PLAYERSKIN
1646                 skin = PRVM_GetString(prog, PRVM_serveredictstring(host_client->edict, playerskin));
1647                 if (skin == NULL)
1648                         skin = "";
1649                 // always point the string back at host_client->name to keep it safe
1650                 //strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1651                 if (skin != host_client->playerskin) // prevent buffer overlap SIGABRT on Mac OSX
1652                         strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1653                 PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
1654
1655                 // TODO: add an extension name for this [1/17/2008 Black]
1656                 clientcamera = PRVM_serveredictedict(host_client->edict, clientcamera);
1657                 if (clientcamera > 0)
1658                 {
1659                         int oldclientcamera = host_client->clientcamera;
1660                         if (clientcamera >= prog->max_edicts || PRVM_EDICT_NUM(clientcamera)->free)
1661                                 clientcamera = PRVM_NUM_FOR_EDICT(host_client->edict);
1662                         host_client->clientcamera = clientcamera;
1663
1664                         if (oldclientcamera != host_client->clientcamera && host_client->netconnection)
1665                         {
1666                                 MSG_WriteByte(&host_client->netconnection->message, svc_setview);
1667                                 MSG_WriteShort(&host_client->netconnection->message, host_client->clientcamera);
1668                         }
1669                 }
1670
1671                 // frags
1672                 host_client->frags = (int)PRVM_serveredictfloat(host_client->edict, frags);
1673                 if(IS_OLDNEXUIZ_DERIVED(gamemode))
1674                         if(!host_client->begun && host_client->netconnection)
1675                                 host_client->frags = -666;
1676                 if (host_client->old_frags != host_client->frags)
1677                 {
1678                         host_client->old_frags = host_client->frags;
1679                         // send notification to all clients
1680                         MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1681                         MSG_WriteByte (&sv.reliable_datagram, i);
1682                         MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1683                 }
1684         }
1685
1686         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1687                 if (client->netconnection && (client->begun || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet
1688                         SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1689
1690         SZ_Clear (&sv.reliable_datagram);
1691 }
1692
1693
1694 /*
1695 =======================
1696 SV_SendClientMessages
1697 =======================
1698 */
1699 void SV_SendClientMessages(void)
1700 {
1701         int i, prepared = false;
1702
1703         if (sv.protocol == PROTOCOL_QUAKEWORLD)
1704                 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1705
1706         SV_FlushBroadcastMessages();
1707
1708 // update frags, names, etc
1709         SV_UpdateToReliableMessages();
1710
1711 // build individual updates
1712         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1713         {
1714                 if (!host_client->active)
1715                         continue;
1716                 if (!host_client->netconnection)
1717                         continue;
1718
1719                 if (host_client->netconnection->message.overflowed)
1720                 {
1721                         SV_DropClient (true, "Buffer overflow in net message"); // if the message couldn't send, kick off
1722                         continue;
1723                 }
1724
1725                 if (!prepared)
1726                 {
1727                         prepared = true;
1728                         // only prepare entities once per frame
1729                         SV_PrepareEntitiesForSending();
1730                 }
1731                 SV_SendClientDatagram(host_client);
1732         }
1733
1734 // clear muzzle flashes
1735         SV_CleanupEnts();
1736 }