• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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