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 // sv_main.c -- server main program
21
22 #include "qwsvdef.h"
23
24 #define CHAN_AUTO 0
25 #define CHAN_WEAPON 1
26 #define CHAN_VOICE 2
27 #define CHAN_ITEM 3
28 #define CHAN_BODY 4
29
30 /*
31 =============================================================================
32
33 Con_Printf redirection
34
35 =============================================================================
36 */
37
38 char outputbuf[8000];
39
40 redirect_t sv_redirected;
41
42 extern cvar_t sv_phs;
43
44 /*
45 ==================
46 SV_FlushRedirect
47 ==================
48 */
SV_FlushRedirect(void)49 void SV_FlushRedirect (void)
50 {
51 char send[8000+6];
52
53 if (sv_redirected == RD_PACKET)
54 {
55 send[0] = 0xff;
56 send[1] = 0xff;
57 send[2] = 0xff;
58 send[3] = 0xff;
59 send[4] = A2C_PRINT;
60 memcpy (send+5, outputbuf, strlen(outputbuf)+1);
61
62 NET_SendPacket (strlen(send)+1, send, net_from);
63 }
64 else if (sv_redirected == RD_CLIENT)
65 {
66 ClientReliableWrite_Begin (host_client, svc_print, strlen(outputbuf)+3);
67 ClientReliableWrite_Byte (host_client, PRINT_HIGH);
68 ClientReliableWrite_String (host_client, outputbuf);
69 }
70
71 // clear it
72 outputbuf[0] = 0;
73 }
74
75
76 /*
77 ==================
78 SV_BeginRedirect
79
80 Send Con_Printf data to the remote client
81 instead of the console
82 ==================
83 */
SV_BeginRedirect(redirect_t rd)84 void SV_BeginRedirect (redirect_t rd)
85 {
86 sv_redirected = rd;
87 outputbuf[0] = 0;
88 }
89
SV_EndRedirect(void)90 void SV_EndRedirect (void)
91 {
92 SV_FlushRedirect ();
93 sv_redirected = RD_NONE;
94 }
95
96
97 /*
98 ================
99 Con_Printf
100
101 Handles cursor positioning, line wrapping, etc
102 ================
103 */
104 #define MAXPRINTMSG 4096
105 // FIXME: make a buffer size safe vsprintf?
Con_Printf(char * fmt,...)106 void Con_Printf (char *fmt, ...)
107 {
108 va_list argptr;
109 char msg[MAXPRINTMSG];
110
111 va_start (argptr,fmt);
112 vsprintf (msg,fmt,argptr);
113 va_end (argptr);
114
115 // add to redirected message
116 if (sv_redirected)
117 {
118 if (strlen (msg) + strlen(outputbuf) > sizeof(outputbuf) - 1)
119 SV_FlushRedirect ();
120 strcat (outputbuf, msg);
121 return;
122 }
123
124 Sys_Printf ("%s", msg); // also echo to debugging console
125 if (sv_logfile)
126 fprintf (sv_logfile, "%s", msg);
127 }
128
129 /*
130 ================
131 Con_DPrintf
132
133 A Con_Printf that only shows up if the "developer" cvar is set
134 ================
135 */
Con_DPrintf(char * fmt,...)136 void Con_DPrintf (char *fmt, ...)
137 {
138 va_list argptr;
139 char msg[MAXPRINTMSG];
140
141 if (!developer.value)
142 return;
143
144 va_start (argptr,fmt);
145 vsprintf (msg,fmt,argptr);
146 va_end (argptr);
147
148 Con_Printf ("%s", msg);
149 }
150
151 /*
152 =============================================================================
153
154 EVENT MESSAGES
155
156 =============================================================================
157 */
158
SV_PrintToClient(client_t * cl,int level,char * string)159 static void SV_PrintToClient(client_t *cl, int level, char *string)
160 {
161 ClientReliableWrite_Begin (cl, svc_print, strlen(string)+3);
162 ClientReliableWrite_Byte (cl, level);
163 ClientReliableWrite_String (cl, string);
164 }
165
166
167 /*
168 =================
169 SV_ClientPrintf
170
171 Sends text across to be displayed if the level passes
172 =================
173 */
SV_ClientPrintf(client_t * cl,int level,char * fmt,...)174 void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
175 {
176 va_list argptr;
177 char string[1024];
178
179 if (level < cl->messagelevel)
180 return;
181
182 va_start (argptr,fmt);
183 vsprintf (string, fmt,argptr);
184 va_end (argptr);
185
186 SV_PrintToClient(cl, level, string);
187 }
188
189 /*
190 =================
191 SV_BroadcastPrintf
192
193 Sends text to all active clients
194 =================
195 */
SV_BroadcastPrintf(int level,char * fmt,...)196 void SV_BroadcastPrintf (int level, char *fmt, ...)
197 {
198 va_list argptr;
199 char string[1024];
200 client_t *cl;
201 int i;
202
203 va_start (argptr,fmt);
204 vsprintf (string, fmt,argptr);
205 va_end (argptr);
206
207 Sys_Printf ("%s", string); // print to the console
208
209 for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
210 {
211 if (level < cl->messagelevel)
212 continue;
213 if (!cl->state)
214 continue;
215
216 SV_PrintToClient(cl, level, string);
217 }
218 }
219
220 /*
221 =================
222 SV_BroadcastCommand
223
224 Sends text to all active clients
225 =================
226 */
SV_BroadcastCommand(char * fmt,...)227 void SV_BroadcastCommand (char *fmt, ...)
228 {
229 va_list argptr;
230 char string[1024];
231
232 if (!sv.state)
233 return;
234 va_start (argptr,fmt);
235 vsprintf (string, fmt,argptr);
236 va_end (argptr);
237
238 MSG_WriteByte (&sv.reliable_datagram, svc_stufftext);
239 MSG_WriteString (&sv.reliable_datagram, string);
240 }
241
242
243 /*
244 =================
245 SV_Multicast
246
247 Sends the contents of sv.multicast to a subset of the clients,
248 then clears sv.multicast.
249
250 MULTICAST_ALL same as broadcast
251 MULTICAST_PVS send to clients potentially visible from org
252 MULTICAST_PHS send to clients potentially hearable from org
253 =================
254 */
SV_Multicast(vec3_t origin,int to)255 void SV_Multicast (vec3_t origin, int to)
256 {
257 client_t *client;
258 byte *mask;
259 mleaf_t *leaf;
260 int leafnum;
261 int j;
262 qboolean reliable;
263
264 leaf = Mod_PointInLeaf (origin, sv.worldmodel);
265 if (!leaf)
266 leafnum = 0;
267 else
268 leafnum = leaf - sv.worldmodel->leafs;
269
270 reliable = false;
271
272 switch (to)
273 {
274 case MULTICAST_ALL_R:
275 reliable = true; // intentional fallthrough
276 case MULTICAST_ALL:
277 mask = sv.pvs; // leaf 0 is everything;
278 break;
279
280 case MULTICAST_PHS_R:
281 reliable = true; // intentional fallthrough
282 case MULTICAST_PHS:
283 mask = sv.phs + leafnum * 4*((sv.worldmodel->numleafs+31)>>5);
284 break;
285
286 case MULTICAST_PVS_R:
287 reliable = true; // intentional fallthrough
288 case MULTICAST_PVS:
289 mask = sv.pvs + leafnum * 4*((sv.worldmodel->numleafs+31)>>5);
290 break;
291
292 default:
293 mask = NULL;
294 SV_Error ("SV_Multicast: bad to:%i", to);
295 }
296
297 // send the data to all relevent clients
298 for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
299 {
300 if (client->state != cs_spawned)
301 continue;
302
303 if (to == MULTICAST_PHS_R || to == MULTICAST_PHS) {
304 vec3_t delta;
305 VectorSubtract(origin, client->edict->v.origin, delta);
306 if (Length(delta) <= 1024)
307 goto inrange;
308 }
309
310 leaf = Mod_PointInLeaf (client->edict->v.origin, sv.worldmodel);
311 if (leaf)
312 {
313 // -1 is because pvs rows are 1 based, not 0 based like leafs
314 leafnum = leaf - sv.worldmodel->leafs - 1;
315 if ( !(mask[leafnum>>3] & (1<<(leafnum&7)) ) )
316 {
317 // Con_Printf ("supressed multicast\n");
318 continue;
319 }
320 }
321
322 inrange:
323 if (reliable) {
324 ClientReliableCheckBlock(client, sv.multicast.cursize);
325 ClientReliableWrite_SZ(client, sv.multicast.data, sv.multicast.cursize);
326 } else
327 SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
328 }
329
330 SZ_Clear (&sv.multicast);
331 }
332
333
334 /*
335 ==================
336 SV_StartSound
337
338 Each entity can have eight independant sound sources, like voice,
339 weapon, feet, etc.
340
341 Channel 0 is an auto-allocate channel, the others override anything
342 allready running on that entity/channel pair.
343
344 An attenuation of 0 will play full volume everywhere in the level.
345 Larger attenuations will drop off. (max 4 attenuation)
346
347 ==================
348 */
SV_StartSound(edict_t * entity,int channel,char * sample,int volume,float attenuation)349 void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,
350 float attenuation)
351 {
352 int sound_num;
353 int field_mask;
354 int i;
355 int ent;
356 vec3_t origin;
357 qboolean use_phs;
358 qboolean reliable = false;
359
360 if (volume < 0 || volume > 255)
361 SV_Error ("SV_StartSound: volume = %i", volume);
362
363 if (attenuation < 0 || attenuation > 4)
364 SV_Error ("SV_StartSound: attenuation = %f", attenuation);
365
366 if (channel < 0 || channel > 15)
367 SV_Error ("SV_StartSound: channel = %i", channel);
368
369 // find precache number for sound
370 for (sound_num=1 ; sound_num<MAX_SOUNDS
371 && sv.sound_precache[sound_num] ; sound_num++)
372 if (!strcmp(sample, sv.sound_precache[sound_num]))
373 break;
374
375 if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] )
376 {
377 Con_Printf ("SV_StartSound: %s not precacheed\n", sample);
378 return;
379 }
380
381 ent = NUM_FOR_EDICT(entity);
382
383 if ((channel & 8) || !sv_phs.value) // no PHS flag
384 {
385 if (channel & 8)
386 reliable = true; // sounds that break the phs are reliable
387 use_phs = false;
388 channel &= 7;
389 }
390 else
391 use_phs = true;
392
393 // if (channel == CHAN_BODY || channel == CHAN_VOICE)
394 // reliable = true;
395
396 channel = (ent<<3) | channel;
397
398 field_mask = 0;
399 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
400 channel |= SND_VOLUME;
401 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
402 channel |= SND_ATTENUATION;
403
404 // use the entity origin unless it is a bmodel
405 if (entity->v.solid == SOLID_BSP)
406 {
407 for (i=0 ; i<3 ; i++)
408 origin[i] = entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]);
409 }
410 else
411 {
412 VectorCopy (entity->v.origin, origin);
413 }
414
415 MSG_WriteByte (&sv.multicast, svc_sound);
416 MSG_WriteShort (&sv.multicast, channel);
417 if (channel & SND_VOLUME)
418 MSG_WriteByte (&sv.multicast, volume);
419 if (channel & SND_ATTENUATION)
420 MSG_WriteByte (&sv.multicast, attenuation*64);
421 MSG_WriteByte (&sv.multicast, sound_num);
422 for (i=0 ; i<3 ; i++)
423 MSG_WriteCoord (&sv.multicast, origin[i]);
424
425 if (use_phs)
426 SV_Multicast (origin, reliable ? MULTICAST_PHS_R : MULTICAST_PHS);
427 else
428 SV_Multicast (origin, reliable ? MULTICAST_ALL_R : MULTICAST_ALL);
429 }
430
431
432 /*
433 ===============================================================================
434
435 FRAME UPDATES
436
437 ===============================================================================
438 */
439
440 int sv_nailmodel, sv_supernailmodel, sv_playermodel;
441
SV_FindModelNumbers(void)442 void SV_FindModelNumbers (void)
443 {
444 int i;
445
446 sv_nailmodel = -1;
447 sv_supernailmodel = -1;
448 sv_playermodel = -1;
449
450 for (i=0 ; i<MAX_MODELS ; i++)
451 {
452 if (!sv.model_precache[i])
453 break;
454 if (!strcmp(sv.model_precache[i],"progs/spike.mdl"))
455 sv_nailmodel = i;
456 if (!strcmp(sv.model_precache[i],"progs/s_spike.mdl"))
457 sv_supernailmodel = i;
458 if (!strcmp(sv.model_precache[i],"progs/player.mdl"))
459 sv_playermodel = i;
460 }
461 }
462
463
464 /*
465 ==================
466 SV_WriteClientdataToMessage
467
468 ==================
469 */
SV_WriteClientdataToMessage(client_t * client,sizebuf_t * msg)470 void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
471 {
472 int i;
473 edict_t *other;
474 edict_t *ent;
475
476 ent = client->edict;
477
478 // send the chokecount for r_netgraph
479 if (client->chokecount)
480 {
481 MSG_WriteByte (msg, svc_chokecount);
482 MSG_WriteByte (msg, client->chokecount);
483 client->chokecount = 0;
484 }
485
486 // send a damage message if the player got hit this frame
487 if (ent->v.dmg_take || ent->v.dmg_save)
488 {
489 other = PROG_TO_EDICT(ent->v.dmg_inflictor);
490 MSG_WriteByte (msg, svc_damage);
491 MSG_WriteByte (msg, ent->v.dmg_save);
492 MSG_WriteByte (msg, ent->v.dmg_take);
493 for (i=0 ; i<3 ; i++)
494 MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));
495
496 ent->v.dmg_take = 0;
497 ent->v.dmg_save = 0;
498 }
499
500 // a fixangle might get lost in a dropped packet. Oh well.
501 if ( ent->v.fixangle )
502 {
503 MSG_WriteByte (msg, svc_setangle);
504 for (i=0 ; i < 3 ; i++)
505 MSG_WriteAngle (msg, ent->v.angles[i] );
506 ent->v.fixangle = 0;
507 }
508 }
509
510 /*
511 =======================
512 SV_UpdateClientStats
513
514 Performs a delta update of the stats array. This should only be performed
515 when a reliable message can be delivered this frame.
516 =======================
517 */
SV_UpdateClientStats(client_t * client)518 void SV_UpdateClientStats (client_t *client)
519 {
520 edict_t *ent;
521 int stats[MAX_CL_STATS];
522 int i;
523
524 ent = client->edict;
525 memset (stats, 0, sizeof(stats));
526
527 // if we are a spectator and we are tracking a player, we get his stats
528 // so our status bar reflects his
529 if (client->spectator && client->spec_track > 0)
530 ent = svs.clients[client->spec_track - 1].edict;
531
532 stats[STAT_HEALTH] = ent->v.health;
533 stats[STAT_WEAPON] = SV_ModelIndex(PR_GetString(ent->v.weaponmodel));
534 stats[STAT_AMMO] = ent->v.currentammo;
535 stats[STAT_ARMOR] = ent->v.armorvalue;
536 stats[STAT_SHELLS] = ent->v.ammo_shells;
537 stats[STAT_NAILS] = ent->v.ammo_nails;
538 stats[STAT_ROCKETS] = ent->v.ammo_rockets;
539 stats[STAT_CELLS] = ent->v.ammo_cells;
540 if (!client->spectator)
541 stats[STAT_ACTIVEWEAPON] = ent->v.weapon;
542 // stuff the sigil bits into the high bits of items for sbar
543 stats[STAT_ITEMS] = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);
544
545 for (i=0 ; i<MAX_CL_STATS ; i++)
546 if (stats[i] != client->stats[i])
547 {
548 client->stats[i] = stats[i];
549 if (stats[i] >=0 && stats[i] <= 255)
550 {
551 ClientReliableWrite_Begin(client, svc_updatestat, 3);
552 ClientReliableWrite_Byte(client, i);
553 ClientReliableWrite_Byte(client, stats[i]);
554 }
555 else
556 {
557 ClientReliableWrite_Begin(client, svc_updatestatlong, 6);
558 ClientReliableWrite_Byte(client, i);
559 ClientReliableWrite_Long(client, stats[i]);
560 }
561 }
562 }
563
564 /*
565 =======================
566 SV_SendClientDatagram
567 =======================
568 */
SV_SendClientDatagram(client_t * client)569 qboolean SV_SendClientDatagram (client_t *client)
570 {
571 byte buf[MAX_DATAGRAM];
572 sizebuf_t msg;
573
574 msg.data = buf;
575 msg.maxsize = sizeof(buf);
576 msg.cursize = 0;
577 msg.allowoverflow = true;
578 msg.overflowed = false;
579
580 // add the client specific data to the datagram
581 SV_WriteClientdataToMessage (client, &msg);
582
583 // send over all the objects that are in the PVS
584 // this will include clients, a packetentities, and
585 // possibly a nails update
586 SV_WriteEntitiesToClient (client, &msg);
587
588 // copy the accumulated multicast datagram
589 // for this client out to the message
590 if (client->datagram.overflowed)
591 Con_Printf ("WARNING: datagram overflowed for %s\n", client->name);
592 else
593 SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
594 SZ_Clear (&client->datagram);
595
596 // send deltas over reliable stream
597 if (Netchan_CanReliable (&client->netchan))
598 SV_UpdateClientStats (client);
599
600 if (msg.overflowed)
601 {
602 Con_Printf ("WARNING: msg overflowed for %s\n", client->name);
603 SZ_Clear (&msg);
604 }
605
606 // send the datagram
607 Netchan_Transmit (&client->netchan, msg.cursize, buf);
608
609 return true;
610 }
611
612 /*
613 =======================
614 SV_UpdateToReliableMessages
615 =======================
616 */
SV_UpdateToReliableMessages(void)617 void SV_UpdateToReliableMessages (void)
618 {
619 int i, j;
620 client_t *client;
621 eval_t *val;
622 edict_t *ent;
623
624 // check for changes to be sent over the reliable streams to all clients
625 for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
626 {
627 if (host_client->state != cs_spawned)
628 continue;
629 if (host_client->sendinfo)
630 {
631 host_client->sendinfo = false;
632 SV_FullClientUpdate (host_client, &sv.reliable_datagram);
633 }
634 if (host_client->old_frags != host_client->edict->v.frags)
635 {
636 for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
637 {
638 if (client->state < cs_connected)
639 continue;
640 ClientReliableWrite_Begin(client, svc_updatefrags, 4);
641 ClientReliableWrite_Byte(client, i);
642 ClientReliableWrite_Short(client, host_client->edict->v.frags);
643 }
644
645 host_client->old_frags = host_client->edict->v.frags;
646 }
647
648 // maxspeed/entgravity changes
649 ent = host_client->edict;
650
651 val = GetEdictFieldValue(ent, "gravity");
652 if (val && host_client->entgravity != val->_float) {
653 host_client->entgravity = val->_float;
654 ClientReliableWrite_Begin(host_client, svc_entgravity, 5);
655 ClientReliableWrite_Float(host_client, host_client->entgravity);
656 }
657 val = GetEdictFieldValue(ent, "maxspeed");
658 if (val && host_client->maxspeed != val->_float) {
659 host_client->maxspeed = val->_float;
660 ClientReliableWrite_Begin(host_client, svc_maxspeed, 5);
661 ClientReliableWrite_Float(host_client, host_client->maxspeed);
662 }
663
664 }
665
666 if (sv.datagram.overflowed)
667 SZ_Clear (&sv.datagram);
668
669 // append the broadcast messages to each client messages
670 for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
671 {
672 if (client->state < cs_connected)
673 continue; // reliables go to all connected or spawned
674
675 ClientReliableCheckBlock(client, sv.reliable_datagram.cursize);
676 ClientReliableWrite_SZ(client, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
677
678 if (client->state != cs_spawned)
679 continue; // datagrams only go to spawned
680 SZ_Write (&client->datagram
681 , sv.datagram.data
682 , sv.datagram.cursize);
683 }
684
685 SZ_Clear (&sv.reliable_datagram);
686 SZ_Clear (&sv.datagram);
687 }
688
689 #ifdef _WIN32
690 #pragma optimize( "", off )
691 #endif
692
693
694
695 /*
696 =======================
697 SV_SendClientMessages
698 =======================
699 */
SV_SendClientMessages(void)700 void SV_SendClientMessages (void)
701 {
702 int i, j;
703 client_t *c;
704
705 // update frags, names, etc
706 SV_UpdateToReliableMessages ();
707
708 // build individual updates
709 for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
710 {
711 if (!c->state)
712 continue;
713
714 if (c->drop) {
715 SV_DropClient(c);
716 c->drop = false;
717 continue;
718 }
719
720 // check to see if we have a backbuf to stick in the reliable
721 if (c->num_backbuf) {
722 // will it fit?
723 if (c->netchan.message.cursize + c->backbuf_size[0] <
724 c->netchan.message.maxsize) {
725
726 Con_DPrintf("%s: backbuf %d bytes\n",
727 c->name, c->backbuf_size[0]);
728
729 // it'll fit
730 SZ_Write(&c->netchan.message, c->backbuf_data[0],
731 c->backbuf_size[0]);
732
733 //move along, move along
734 for (j = 1; j < c->num_backbuf; j++) {
735 memcpy(c->backbuf_data[j - 1], c->backbuf_data[j],
736 c->backbuf_size[j]);
737 c->backbuf_size[j - 1] = c->backbuf_size[j];
738 }
739
740 c->num_backbuf--;
741 if (c->num_backbuf) {
742 memset(&c->backbuf, 0, sizeof(c->backbuf));
743 c->backbuf.data = c->backbuf_data[c->num_backbuf - 1];
744 c->backbuf.cursize = c->backbuf_size[c->num_backbuf - 1];
745 c->backbuf.maxsize = sizeof(c->backbuf_data[c->num_backbuf - 1]);
746 }
747 }
748 }
749
750 // if the reliable message overflowed,
751 // drop the client
752 if (c->netchan.message.overflowed)
753 {
754 SZ_Clear (&c->netchan.message);
755 SZ_Clear (&c->datagram);
756 SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
757 Con_Printf ("WARNING: reliable overflow for %s\n",c->name);
758 SV_DropClient (c);
759 c->send_message = true;
760 c->netchan.cleartime = 0; // don't choke this message
761 }
762
763 // only send messages if the client has sent one
764 // and the bandwidth is not choked
765 if (!c->send_message)
766 continue;
767 c->send_message = false; // try putting this after choke?
768 if (!sv.paused && !Netchan_CanPacket (&c->netchan))
769 {
770 c->chokecount++;
771 continue; // bandwidth choke
772 }
773
774 if (c->state == cs_spawned)
775 SV_SendClientDatagram (c);
776 else
777 Netchan_Transmit (&c->netchan, 0, NULL); // just update reliable
778
779 }
780 }
781
782 #ifdef _WIN32
783 #pragma optimize( "", on )
784 #endif
785
786
787
788 /*
789 =======================
790 SV_SendMessagesToAll
791
792 FIXME: does this sequence right?
793 =======================
794 */
SV_SendMessagesToAll(void)795 void SV_SendMessagesToAll (void)
796 {
797 int i;
798 client_t *c;
799
800 for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
801 if (c->state) // FIXME: should this only send to active?
802 c->send_message = true;
803
804 SV_SendClientMessages ();
805 }
806
807