Home | History | Annotate | Download | only in server
      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_user.c -- server code for moving users
     21 
     22 #include "qwsvdef.h"
     23 
     24 edict_t	*sv_player;
     25 
     26 usercmd_t	cmd;
     27 
     28 cvar_t	cl_rollspeed = {"cl_rollspeed", "200"};
     29 cvar_t	cl_rollangle = {"cl_rollangle", "2.0"};
     30 cvar_t	sv_spectalk = {"sv_spectalk", "1"};
     31 
     32 cvar_t	sv_mapcheck	= {"sv_mapcheck", "1"};
     33 
     34 extern	vec3_t	player_mins;
     35 
     36 extern int fp_messages, fp_persecond, fp_secondsdead;
     37 extern char fp_msg[];
     38 extern cvar_t pausable;
     39 
     40 /*
     41 ============================================================
     42 
     43 USER STRINGCMD EXECUTION
     44 
     45 host_client and sv_player will be valid.
     46 ============================================================
     47 */
     48 
     49 /*
     50 ================
     51 SV_New_f
     52 
     53 Sends the first message from the server to a connected client.
     54 This will be sent on the initial connection and upon each server load.
     55 ================
     56 */
     57 void SV_New_f (void)
     58 {
     59 	char		*gamedir;
     60 	int			playernum;
     61 
     62 	if (host_client->state == cs_spawned)
     63 		return;
     64 
     65 	host_client->state = cs_connected;
     66 	host_client->connection_started = realtime;
     67 
     68 	// send the info about the new client to all connected clients
     69 //	SV_FullClientUpdate (host_client, &sv.reliable_datagram);
     70 //	host_client->sendinfo = true;
     71 
     72 	gamedir = Info_ValueForKey (svs.info, "*gamedir");
     73 	if (!gamedir[0])
     74 		gamedir = "qw";
     75 
     76 //NOTE:  This doesn't go through ClientReliableWrite since it's before the user
     77 //spawns.  These functions are written to not overflow
     78 	if (host_client->num_backbuf) {
     79 		Con_Printf("WARNING %s: [SV_New] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
     80 		host_client->num_backbuf = 0;
     81 		SZ_Clear(&host_client->netchan.message);
     82 	}
     83 
     84 	// send the serverdata
     85 	MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
     86 	MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION);
     87 	MSG_WriteLong (&host_client->netchan.message, svs.spawncount);
     88 	MSG_WriteString (&host_client->netchan.message, gamedir);
     89 
     90 	playernum = NUM_FOR_EDICT(host_client->edict)-1;
     91 	if (host_client->spectator)
     92 		playernum |= 128;
     93 	MSG_WriteByte (&host_client->netchan.message, playernum);
     94 
     95 	// send full levelname
     96 	MSG_WriteString (&host_client->netchan.message, PR_GetString(sv.edicts->v.message));
     97 
     98 	// send the movevars
     99 	MSG_WriteFloat(&host_client->netchan.message, movevars.gravity);
    100 	MSG_WriteFloat(&host_client->netchan.message, movevars.stopspeed);
    101 	MSG_WriteFloat(&host_client->netchan.message, movevars.maxspeed);
    102 	MSG_WriteFloat(&host_client->netchan.message, movevars.spectatormaxspeed);
    103 	MSG_WriteFloat(&host_client->netchan.message, movevars.accelerate);
    104 	MSG_WriteFloat(&host_client->netchan.message, movevars.airaccelerate);
    105 	MSG_WriteFloat(&host_client->netchan.message, movevars.wateraccelerate);
    106 	MSG_WriteFloat(&host_client->netchan.message, movevars.friction);
    107 	MSG_WriteFloat(&host_client->netchan.message, movevars.waterfriction);
    108 	MSG_WriteFloat(&host_client->netchan.message, movevars.entgravity);
    109 
    110 	// send music
    111 	MSG_WriteByte (&host_client->netchan.message, svc_cdtrack);
    112 	MSG_WriteByte (&host_client->netchan.message, sv.edicts->v.sounds);
    113 
    114 	// send server info string
    115 	MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
    116 	MSG_WriteString (&host_client->netchan.message, va("fullserverinfo \"%s\"\n", svs.info) );
    117 }
    118 
    119 /*
    120 ==================
    121 SV_Soundlist_f
    122 ==================
    123 */
    124 void SV_Soundlist_f (void)
    125 {
    126 	char		**s;
    127 	int			n;
    128 
    129 	if (host_client->state != cs_connected)
    130 	{
    131 		Con_Printf ("soundlist not valid -- allready spawned\n");
    132 		return;
    133 	}
    134 
    135 	// handle the case of a level changing while a client was connecting
    136 	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
    137 	{
    138 		Con_Printf ("SV_Soundlist_f from different level\n");
    139 		SV_New_f ();
    140 		return;
    141 	}
    142 
    143 	n = atoi(Cmd_Argv(2));
    144 
    145 //NOTE:  This doesn't go through ClientReliableWrite since it's before the user
    146 //spawns.  These functions are written to not overflow
    147 	if (host_client->num_backbuf) {
    148 		Con_Printf("WARNING %s: [SV_Soundlist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
    149 		host_client->num_backbuf = 0;
    150 		SZ_Clear(&host_client->netchan.message);
    151 	}
    152 
    153 	MSG_WriteByte (&host_client->netchan.message, svc_soundlist);
    154 	MSG_WriteByte (&host_client->netchan.message, n);
    155 	for (s = sv.sound_precache+1 + n ;
    156 		*s && host_client->netchan.message.cursize < (MAX_MSGLEN/2);
    157 		s++, n++)
    158 		MSG_WriteString (&host_client->netchan.message, *s);
    159 
    160 	MSG_WriteByte (&host_client->netchan.message, 0);
    161 
    162 	// next msg
    163 	if (*s)
    164 		MSG_WriteByte (&host_client->netchan.message, n);
    165 	else
    166 		MSG_WriteByte (&host_client->netchan.message, 0);
    167 }
    168 
    169 /*
    170 ==================
    171 SV_Modellist_f
    172 ==================
    173 */
    174 void SV_Modellist_f (void)
    175 {
    176 	char		**s;
    177 	int			n;
    178 
    179 	if (host_client->state != cs_connected)
    180 	{
    181 		Con_Printf ("modellist not valid -- allready spawned\n");
    182 		return;
    183 	}
    184 
    185 	// handle the case of a level changing while a client was connecting
    186 	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
    187 	{
    188 		Con_Printf ("SV_Modellist_f from different level\n");
    189 		SV_New_f ();
    190 		return;
    191 	}
    192 
    193 	n = atoi(Cmd_Argv(2));
    194 
    195 //NOTE:  This doesn't go through ClientReliableWrite since it's before the user
    196 //spawns.  These functions are written to not overflow
    197 	if (host_client->num_backbuf) {
    198 		Con_Printf("WARNING %s: [SV_Modellist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
    199 		host_client->num_backbuf = 0;
    200 		SZ_Clear(&host_client->netchan.message);
    201 	}
    202 
    203 	MSG_WriteByte (&host_client->netchan.message, svc_modellist);
    204 	MSG_WriteByte (&host_client->netchan.message, n);
    205 	for (s = sv.model_precache+1+n ;
    206 		*s && host_client->netchan.message.cursize < (MAX_MSGLEN/2);
    207 		s++, n++)
    208 		MSG_WriteString (&host_client->netchan.message, *s);
    209 	MSG_WriteByte (&host_client->netchan.message, 0);
    210 
    211 	// next msg
    212 	if (*s)
    213 		MSG_WriteByte (&host_client->netchan.message, n);
    214 	else
    215 		MSG_WriteByte (&host_client->netchan.message, 0);
    216 }
    217 
    218 /*
    219 ==================
    220 SV_PreSpawn_f
    221 ==================
    222 */
    223 void SV_PreSpawn_f (void)
    224 {
    225 	unsigned	buf;
    226 	unsigned	check;
    227 
    228 	if (host_client->state != cs_connected)
    229 	{
    230 		Con_Printf ("prespawn not valid -- allready spawned\n");
    231 		return;
    232 	}
    233 
    234 	// handle the case of a level changing while a client was connecting
    235 	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
    236 	{
    237 		Con_Printf ("SV_PreSpawn_f from different level\n");
    238 		SV_New_f ();
    239 		return;
    240 	}
    241 
    242 	buf = atoi(Cmd_Argv(2));
    243 	if (buf >= sv.num_signon_buffers)
    244 		buf = 0;
    245 
    246 	if (!buf) {
    247 		// should be three numbers following containing checksums
    248 		check = atoi(Cmd_Argv(3));
    249 
    250 //		Con_DPrintf("Client check = %d\n", check);
    251 
    252 		if (sv_mapcheck.value && check != sv.worldmodel->checksum &&
    253 			check != sv.worldmodel->checksum2) {
    254 			SV_ClientPrintf (host_client, PRINT_HIGH,
    255 				"Map model file does not match (%s), %i != %i/%i.\n"
    256 				"You may need a new version of the map, or the proper install files.\n",
    257 				sv.modelname, check, sv.worldmodel->checksum, sv.worldmodel->checksum2);
    258 			SV_DropClient (host_client);
    259 			return;
    260 		}
    261 		host_client->checksum = check;
    262 	}
    263 
    264 //NOTE:  This doesn't go through ClientReliableWrite since it's before the user
    265 //spawns.  These functions are written to not overflow
    266 	if (host_client->num_backbuf) {
    267 		Con_Printf("WARNING %s: [SV_PreSpawn] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
    268 		host_client->num_backbuf = 0;
    269 		SZ_Clear(&host_client->netchan.message);
    270 	}
    271 
    272 	SZ_Write (&host_client->netchan.message,
    273 		sv.signon_buffers[buf],
    274 		sv.signon_buffer_size[buf]);
    275 
    276 	buf++;
    277 	if (buf == sv.num_signon_buffers)
    278 	{	// all done prespawning
    279 		MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
    280 		MSG_WriteString (&host_client->netchan.message, va("cmd spawn %i 0\n",svs.spawncount) );
    281 	}
    282 	else
    283 	{	// need to prespawn more
    284 		MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
    285 		MSG_WriteString (&host_client->netchan.message,
    286 			va("cmd prespawn %i %i\n", svs.spawncount, buf) );
    287 	}
    288 }
    289 
    290 /*
    291 ==================
    292 SV_Spawn_f
    293 ==================
    294 */
    295 void SV_Spawn_f (void)
    296 {
    297 	int		i;
    298 	client_t	*client;
    299 	edict_t	*ent;
    300 	eval_t *val;
    301 	int n;
    302 
    303 	if (host_client->state != cs_connected)
    304 	{
    305 		Con_Printf ("Spawn not valid -- allready spawned\n");
    306 		return;
    307 	}
    308 
    309 // handle the case of a level changing while a client was connecting
    310 	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
    311 	{
    312 		Con_Printf ("SV_Spawn_f from different level\n");
    313 		SV_New_f ();
    314 		return;
    315 	}
    316 
    317 	n = atoi(Cmd_Argv(2));
    318 
    319 	// make sure n is valid
    320 	if ( n < 0 || n > MAX_CLIENTS )
    321 	{
    322 		Con_Printf ("SV_Spawn_f invalid client start\n");
    323 		SV_New_f ();
    324 		return;
    325 	}
    326 
    327 
    328 
    329 // send all current names, colors, and frag counts
    330 	// FIXME: is this a good thing?
    331 	SZ_Clear (&host_client->netchan.message);
    332 
    333 // send current status of all other players
    334 
    335 	// normally this could overflow, but no need to check due to backbuf
    336 	for (i=n, client = svs.clients + n ; i<MAX_CLIENTS ; i++, client++)
    337 		SV_FullClientUpdateToClient (client, host_client);
    338 
    339 // send all current light styles
    340 	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
    341 	{
    342 		ClientReliableWrite_Begin (host_client, svc_lightstyle,
    343 			3 + (sv.lightstyles[i] ? strlen(sv.lightstyles[i]) : 1));
    344 		ClientReliableWrite_Byte (host_client, (char)i);
    345 		ClientReliableWrite_String (host_client, sv.lightstyles[i]);
    346 	}
    347 
    348 	// set up the edict
    349 	ent = host_client->edict;
    350 
    351 	memset (&ent->v, 0, progs->entityfields * 4);
    352 	ent->v.colormap = NUM_FOR_EDICT(ent);
    353 	ent->v.team = 0;	// FIXME
    354 	ent->v.netname = PR_SetString(host_client->name);
    355 
    356 	host_client->entgravity = 1.0;
    357 	val = GetEdictFieldValue(ent, "gravity");
    358 	if (val)
    359 		val->_float = 1.0;
    360 	host_client->maxspeed = sv_maxspeed.value;
    361 	val = GetEdictFieldValue(ent, "maxspeed");
    362 	if (val)
    363 		val->_float = sv_maxspeed.value;
    364 
    365 //
    366 // force stats to be updated
    367 //
    368 	memset (host_client->stats, 0, sizeof(host_client->stats));
    369 
    370 	ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
    371 	ClientReliableWrite_Byte (host_client, STAT_TOTALSECRETS);
    372 	ClientReliableWrite_Long (host_client, pr_global_struct->total_secrets);
    373 
    374 	ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
    375 	ClientReliableWrite_Byte (host_client, STAT_TOTALMONSTERS);
    376 	ClientReliableWrite_Long (host_client, pr_global_struct->total_monsters);
    377 
    378 	ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
    379 	ClientReliableWrite_Byte (host_client, STAT_SECRETS);
    380 	ClientReliableWrite_Long (host_client, pr_global_struct->found_secrets);
    381 
    382 	ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
    383 	ClientReliableWrite_Byte (host_client, STAT_MONSTERS);
    384 	ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters);
    385 
    386 	// get the client to check and download skins
    387 	// when that is completed, a begin command will be issued
    388 	ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
    389 	ClientReliableWrite_String (host_client, "skins\n" );
    390 
    391 }
    392 
    393 /*
    394 ==================
    395 SV_SpawnSpectator
    396 ==================
    397 */
    398 void SV_SpawnSpectator (void)
    399 {
    400 	int		i;
    401 	edict_t	*e;
    402 
    403 	VectorCopy (vec3_origin, sv_player->v.origin);
    404 	VectorCopy (vec3_origin, sv_player->v.view_ofs);
    405 	sv_player->v.view_ofs[2] = 22;
    406 
    407 	// search for an info_playerstart to spawn the spectator at
    408 	for (i=MAX_CLIENTS-1 ; i<sv.num_edicts ; i++)
    409 	{
    410 		e = EDICT_NUM(i);
    411 		if (!strcmp(PR_GetString(e->v.classname), "info_player_start"))
    412 		{
    413 			VectorCopy (e->v.origin, sv_player->v.origin);
    414 			return;
    415 		}
    416 	}
    417 
    418 }
    419 
    420 /*
    421 ==================
    422 SV_Begin_f
    423 ==================
    424 */
    425 void SV_Begin_f (void)
    426 {
    427 	unsigned pmodel = 0, emodel = 0;
    428 	int		i;
    429 
    430 	if (host_client->state == cs_spawned)
    431 		return; // don't begin again
    432 
    433 	host_client->state = cs_spawned;
    434 
    435 	// handle the case of a level changing while a client was connecting
    436 	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
    437 	{
    438 		Con_Printf ("SV_Begin_f from different level\n");
    439 		SV_New_f ();
    440 		return;
    441 	}
    442 
    443 	if (host_client->spectator)
    444 	{
    445 		SV_SpawnSpectator ();
    446 
    447 		if (SpectatorConnect) {
    448 			// copy spawn parms out of the client_t
    449 			for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
    450 				(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
    451 
    452 			// call the spawn function
    453 			pr_global_struct->time = sv.time;
    454 			pr_global_struct->self = EDICT_TO_PROG(sv_player);
    455 			PR_ExecuteProgram (SpectatorConnect);
    456 		}
    457 	}
    458 	else
    459 	{
    460 		// copy spawn parms out of the client_t
    461 		for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
    462 			(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
    463 
    464 		// call the spawn function
    465 		pr_global_struct->time = sv.time;
    466 		pr_global_struct->self = EDICT_TO_PROG(sv_player);
    467 		PR_ExecuteProgram (pr_global_struct->ClientConnect);
    468 
    469 		// actually spawn the player
    470 		pr_global_struct->time = sv.time;
    471 		pr_global_struct->self = EDICT_TO_PROG(sv_player);
    472 		PR_ExecuteProgram (pr_global_struct->PutClientInServer);
    473 	}
    474 
    475 	// clear the net statistics, because connecting gives a bogus picture
    476 	host_client->netchan.frame_latency = 0;
    477 	host_client->netchan.frame_rate = 0;
    478 	host_client->netchan.drop_count = 0;
    479 	host_client->netchan.good_count = 0;
    480 
    481 	//check he's not cheating
    482 
    483 	pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel"));
    484 	emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel"));
    485 
    486 	if (pmodel != sv.model_player_checksum ||
    487 		emodel != sv.eyes_player_checksum)
    488 		SV_BroadcastPrintf (PRINT_HIGH, "%s WARNING: non standard player/eyes model detected\n", host_client->name);
    489 
    490 	// if we are paused, tell the client
    491 	if (sv.paused) {
    492 		ClientReliableWrite_Begin (host_client, svc_setpause, 2);
    493 		ClientReliableWrite_Byte (host_client, sv.paused);
    494 		SV_ClientPrintf(host_client, PRINT_HIGH, "Server is paused.\n");
    495 	}
    496 
    497 #if 0
    498 //
    499 // send a fixangle over the reliable channel to make sure it gets there
    500 // Never send a roll angle, because savegames can catch the server
    501 // in a state where it is expecting the client to correct the angle
    502 // and it won't happen if the game was just loaded, so you wind up
    503 // with a permanent head tilt
    504 	ent = EDICT_NUM( 1 + (host_client - svs.clients) );
    505 	MSG_WriteByte (&host_client->netchan.message, svc_setangle);
    506 	for (i=0 ; i < 2 ; i++)
    507 		MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] );
    508 	MSG_WriteAngle (&host_client->netchan.message, 0 );
    509 #endif
    510 }
    511 
    512 //=============================================================================
    513 
    514 /*
    515 ==================
    516 SV_NextDownload_f
    517 ==================
    518 */
    519 void SV_NextDownload_f (void)
    520 {
    521 	byte	buffer[1024];
    522 	int		r;
    523 	int		percent;
    524 	int		size;
    525 
    526 	if (!host_client->download)
    527 		return;
    528 
    529 	r = host_client->downloadsize - host_client->downloadcount;
    530 	if (r > 768)
    531 		r = 768;
    532 	r = fread (buffer, 1, r, host_client->download);
    533 	ClientReliableWrite_Begin (host_client, svc_download, 6+r);
    534 	ClientReliableWrite_Short (host_client, r);
    535 
    536 	host_client->downloadcount += r;
    537 	size = host_client->downloadsize;
    538 	if (!size)
    539 		size = 1;
    540 	percent = host_client->downloadcount*100/size;
    541 	ClientReliableWrite_Byte (host_client, percent);
    542 	ClientReliableWrite_SZ (host_client, buffer, r);
    543 
    544 	if (host_client->downloadcount != host_client->downloadsize)
    545 		return;
    546 
    547 	fclose (host_client->download);
    548 	host_client->download = NULL;
    549 
    550 }
    551 
    552 void OutofBandPrintf(netadr_t where, char *fmt, ...)
    553 {
    554 	va_list		argptr;
    555 	char	send[1024];
    556 
    557 	send[0] = 0xff;
    558 	send[1] = 0xff;
    559 	send[2] = 0xff;
    560 	send[3] = 0xff;
    561 	send[4] = A2C_PRINT;
    562 	va_start (argptr, fmt);
    563 	vsprintf (send+5, fmt, argptr);
    564 	va_end (argptr);
    565 
    566 	NET_SendPacket (strlen(send)+1, send, where);
    567 }
    568 
    569 /*
    570 ==================
    571 SV_NextUpload
    572 ==================
    573 */
    574 void SV_NextUpload (void)
    575 {
    576 	byte	buffer[1024];
    577 	int		r;
    578 	int		percent;
    579 	int		size;
    580 	client_t *client;
    581 
    582 	if (!*host_client->uploadfn) {
    583 		SV_ClientPrintf(host_client, PRINT_HIGH, "Upload denied\n");
    584 		ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
    585 		ClientReliableWrite_String (host_client, "stopul");
    586 
    587 		// suck out rest of packet
    588 		size = MSG_ReadShort ();	MSG_ReadByte ();
    589 		msg_readcount += size;
    590 		return;
    591 	}
    592 
    593 	size = MSG_ReadShort ();
    594 	percent = MSG_ReadByte ();
    595 
    596 	if (!host_client->upload)
    597 	{
    598 		host_client->upload = fopen(host_client->uploadfn, "wb");
    599 		if (!host_client->upload) {
    600 			Sys_Printf("Can't create %s\n", host_client->uploadfn);
    601 			ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
    602 			ClientReliableWrite_String (host_client, "stopul");
    603 			*host_client->uploadfn = 0;
    604 			return;
    605 		}
    606 		Sys_Printf("Receiving %s from %d...\n", host_client->uploadfn, host_client->userid);
    607 		if (host_client->remote_snap)
    608 			OutofBandPrintf(host_client->snap_from, "Server receiving %s from %d...\n", host_client->uploadfn, host_client->userid);
    609 	}
    610 
    611 	fwrite (net_message.data + msg_readcount, 1, size, host_client->upload);
    612 	msg_readcount += size;
    613 
    614 Con_DPrintf ("UPLOAD: %d received\n", size);
    615 
    616 	if (percent != 100) {
    617 		ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
    618 		ClientReliableWrite_String (host_client, "nextul\n");
    619 	} else {
    620 		fclose (host_client->upload);
    621 		host_client->upload = NULL;
    622 
    623 		Sys_Printf("%s upload completed.\n", host_client->uploadfn);
    624 
    625 		if (host_client->remote_snap) {
    626 			char *p;
    627 
    628 			if ((p = strchr(host_client->uploadfn, '/')) != NULL)
    629 				p++;
    630 			else
    631 				p = host_client->uploadfn;
    632 			OutofBandPrintf(host_client->snap_from, "%s upload completed.\nTo download, enter:\ndownload %s\n",
    633 				host_client->uploadfn, p);
    634 		}
    635 	}
    636 
    637 }
    638 
    639 /*
    640 ==================
    641 SV_BeginDownload_f
    642 ==================
    643 */
    644 void SV_BeginDownload_f(void)
    645 {
    646 	char	*name;
    647 	extern	cvar_t	allow_download;
    648 	extern	cvar_t	allow_download_skins;
    649 	extern	cvar_t	allow_download_models;
    650 	extern	cvar_t	allow_download_sounds;
    651 	extern	cvar_t	allow_download_maps;
    652 	extern	int		file_from_pak; // ZOID did file come from pak?
    653 
    654 	name = Cmd_Argv(1);
    655 // hacked by zoid to allow more conrol over download
    656 		// first off, no .. or global allow check
    657 	if (strstr (name, "..") || !allow_download.value
    658 		// leading dot is no good
    659 		|| *name == '.'
    660 		// leading slash bad as well, must be in subdir
    661 		|| *name == '/'
    662 		// next up, skin check
    663 		|| (strncmp(name, "skins/", 6) == 0 && !allow_download_skins.value)
    664 		// now models
    665 		|| (strncmp(name, "progs/", 6) == 0 && !allow_download_models.value)
    666 		// now sounds
    667 		|| (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds.value)
    668 		// now maps (note special case for maps, must not be in pak)
    669 		|| (strncmp(name, "maps/", 6) == 0 && !allow_download_maps.value)
    670 		// MUST be in a subdirectory
    671 		|| !strstr (name, "/") )
    672 	{	// don't allow anything with .. path
    673 		ClientReliableWrite_Begin (host_client, svc_download, 4);
    674 		ClientReliableWrite_Short (host_client, -1);
    675 		ClientReliableWrite_Byte (host_client, 0);
    676 		return;
    677 	}
    678 
    679 	if (host_client->download) {
    680 		fclose (host_client->download);
    681 		host_client->download = NULL;
    682 	}
    683 
    684 	// lowercase name (needed for casesen file systems)
    685 	{
    686 		char *p;
    687 
    688 		for (p = name; *p; p++)
    689 			*p = (char)tolower(*p);
    690 	}
    691 
    692 
    693 	host_client->downloadsize = COM_FOpenFile (name, &host_client->download);
    694 	host_client->downloadcount = 0;
    695 
    696 	if (!host_client->download
    697 		// special check for maps, if it came from a pak file, don't allow
    698 		// download  ZOID
    699 		|| (strncmp(name, "maps/", 5) == 0 && file_from_pak))
    700 	{
    701 		if (host_client->download) {
    702 			fclose(host_client->download);
    703 			host_client->download = NULL;
    704 		}
    705 
    706 		Sys_Printf ("Couldn't download %s to %s\n", name, host_client->name);
    707 		ClientReliableWrite_Begin (host_client, svc_download, 4);
    708 		ClientReliableWrite_Short (host_client, -1);
    709 		ClientReliableWrite_Byte (host_client, 0);
    710 		return;
    711 	}
    712 
    713 	SV_NextDownload_f ();
    714 	Sys_Printf ("Downloading %s to %s\n", name, host_client->name);
    715 }
    716 
    717 //=============================================================================
    718 
    719 /*
    720 ==================
    721 SV_Say
    722 ==================
    723 */
    724 void SV_Say (qboolean team)
    725 {
    726 	client_t *client;
    727 	int		j, tmp;
    728 	char	*p;
    729 	char	text[2048];
    730 	char	t1[32], *t2;
    731 
    732 	if (Cmd_Argc () < 2)
    733 		return;
    734 
    735 	if (team)
    736 	{
    737 		strncpy (t1, Info_ValueForKey (host_client->userinfo, "team"), 31);
    738 		t1[31] = 0;
    739 	}
    740 
    741 	if (host_client->spectator && (!sv_spectalk.value || team))
    742 		sprintf (text, "[SPEC] %s: ", host_client->name);
    743 	else if (team)
    744 		sprintf (text, "(%s): ", host_client->name);
    745 	else {
    746 		sprintf (text, "%s: ", host_client->name);
    747 	}
    748 
    749 	if (fp_messages) {
    750 		if (!sv.paused && realtime<host_client->lockedtill) {
    751 			SV_ClientPrintf(host_client, PRINT_CHAT,
    752 				"You can't talk for %d more seconds\n",
    753 					(int) (host_client->lockedtill - realtime));
    754 			return;
    755 		}
    756 		tmp = host_client->whensaidhead - fp_messages + 1;
    757 		if (tmp < 0)
    758 			tmp = 10+tmp;
    759 		if (!sv.paused &&
    760 			host_client->whensaid[tmp] && (realtime-host_client->whensaid[tmp] < fp_persecond)) {
    761 			host_client->lockedtill = realtime + fp_secondsdead;
    762 			if (fp_msg[0])
    763 				SV_ClientPrintf(host_client, PRINT_CHAT,
    764 					"FloodProt: %s\n", fp_msg);
    765 			else
    766 				SV_ClientPrintf(host_client, PRINT_CHAT,
    767 					"FloodProt: You can't talk for %d seconds.\n", fp_secondsdead);
    768 			return;
    769 		}
    770 		host_client->whensaidhead++;
    771 		if (host_client->whensaidhead > 9)
    772 			host_client->whensaidhead = 0;
    773 		host_client->whensaid[host_client->whensaidhead] = realtime;
    774 	}
    775 
    776 	p = Cmd_Args();
    777 
    778 	if (*p == '"')
    779 	{
    780 		p++;
    781 		p[Q_strlen(p)-1] = 0;
    782 	}
    783 
    784 	Q_strcat(text, p);
    785 	Q_strcat(text, "\n");
    786 
    787 	Sys_Printf ("%s", text);
    788 
    789 	for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
    790 	{
    791 		if (client->state != cs_spawned)
    792 			continue;
    793 		if (host_client->spectator && !sv_spectalk.value)
    794 			if (!client->spectator)
    795 				continue;
    796 
    797 		if (team)
    798 		{
    799 			// the spectator team
    800 			if (host_client->spectator) {
    801 				if (!client->spectator)
    802 					continue;
    803 			} else {
    804 				t2 = Info_ValueForKey (client->userinfo, "team");
    805 				if (strcmp(t1, t2) || client->spectator)
    806 					continue;	// on different teams
    807 			}
    808 		}
    809 		SV_ClientPrintf(client, PRINT_CHAT, "%s", text);
    810 	}
    811 }
    812 
    813 
    814 /*
    815 ==================
    816 SV_Say_f
    817 ==================
    818 */
    819 void SV_Say_f(void)
    820 {
    821 	SV_Say (false);
    822 }
    823 /*
    824 ==================
    825 SV_Say_Team_f
    826 ==================
    827 */
    828 void SV_Say_Team_f(void)
    829 {
    830 	SV_Say (true);
    831 }
    832 
    833 
    834 
    835 //============================================================================
    836 
    837 /*
    838 =================
    839 SV_Pings_f
    840 
    841 The client is showing the scoreboard, so send new ping times for all
    842 clients
    843 =================
    844 */
    845 void SV_Pings_f (void)
    846 {
    847 	client_t *client;
    848 	int		j;
    849 
    850 	for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
    851 	{
    852 		if (client->state != cs_spawned)
    853 			continue;
    854 
    855 		ClientReliableWrite_Begin (host_client, svc_updateping, 4);
    856 		ClientReliableWrite_Byte (host_client, j);
    857 		ClientReliableWrite_Short (host_client, SV_CalcPing(client));
    858 		ClientReliableWrite_Begin (host_client, svc_updatepl, 4);
    859 		ClientReliableWrite_Byte (host_client, j);
    860 		ClientReliableWrite_Byte (host_client, client->lossage);
    861 	}
    862 }
    863 
    864 
    865 
    866 /*
    867 ==================
    868 SV_Kill_f
    869 ==================
    870 */
    871 void SV_Kill_f (void)
    872 {
    873 	if (sv_player->v.health <= 0)
    874 	{
    875 		SV_ClientPrintf (host_client, PRINT_HIGH, "Can't suicide -- allready dead!\n");
    876 		return;
    877 	}
    878 
    879 	pr_global_struct->time = sv.time;
    880 	pr_global_struct->self = EDICT_TO_PROG(sv_player);
    881 	PR_ExecuteProgram (pr_global_struct->ClientKill);
    882 }
    883 
    884 /*
    885 ==================
    886 SV_TogglePause
    887 ==================
    888 */
    889 void SV_TogglePause (const char *msg)
    890 {
    891 	int i;
    892 	client_t *cl;
    893 
    894 	sv.paused ^= 1;
    895 
    896 	if (msg)
    897 		SV_BroadcastPrintf (PRINT_HIGH, "%s", msg);
    898 
    899 	// send notification to all clients
    900 	for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
    901 	{
    902 		if (!cl->state)
    903 			continue;
    904 		ClientReliableWrite_Begin (cl, svc_setpause, 2);
    905 		ClientReliableWrite_Byte (cl, sv.paused);
    906 	}
    907 }
    908 
    909 
    910 /*
    911 ==================
    912 SV_Pause_f
    913 ==================
    914 */
    915 void SV_Pause_f (void)
    916 {
    917 	int i;
    918 	client_t *cl;
    919 	char st[sizeof(host_client->name) + 32];
    920 
    921 	if (!pausable.value) {
    922 		SV_ClientPrintf (host_client, PRINT_HIGH, "Pause not allowed.\n");
    923 		return;
    924 	}
    925 
    926 	if (host_client->spectator) {
    927 		SV_ClientPrintf (host_client, PRINT_HIGH, "Spectators can not pause.\n");
    928 		return;
    929 	}
    930 
    931 	if (sv.paused)
    932 		sprintf (st, "%s paused the game\n", host_client->name);
    933 	else
    934 		sprintf (st, "%s unpaused the game\n", host_client->name);
    935 
    936 	SV_TogglePause(st);
    937 }
    938 
    939 
    940 /*
    941 =================
    942 SV_Drop_f
    943 
    944 The client is going to disconnect, so remove the connection immediately
    945 =================
    946 */
    947 void SV_Drop_f (void)
    948 {
    949 	SV_EndRedirect ();
    950 	if (!host_client->spectator)
    951 		SV_BroadcastPrintf (PRINT_HIGH, "%s dropped\n", host_client->name);
    952 	SV_DropClient (host_client);
    953 }
    954 
    955 /*
    956 =================
    957 SV_PTrack_f
    958 
    959 Change the bandwidth estimate for a client
    960 =================
    961 */
    962 void SV_PTrack_f (void)
    963 {
    964 	int		i;
    965 	edict_t *ent, *tent;
    966 
    967 	if (!host_client->spectator)
    968 		return;
    969 
    970 	if (Cmd_Argc() != 2)
    971 	{
    972 		// turn off tracking
    973 		host_client->spec_track = 0;
    974 		ent = EDICT_NUM(host_client - svs.clients + 1);
    975 		tent = EDICT_NUM(0);
    976 		ent->v.goalentity = EDICT_TO_PROG(tent);
    977 		return;
    978 	}
    979 
    980 	i = atoi(Cmd_Argv(1));
    981 	if (i < 0 || i >= MAX_CLIENTS || svs.clients[i].state != cs_spawned ||
    982 		svs.clients[i].spectator) {
    983 		SV_ClientPrintf (host_client, PRINT_HIGH, "Invalid client to track\n");
    984 		host_client->spec_track = 0;
    985 		ent = EDICT_NUM(host_client - svs.clients + 1);
    986 		tent = EDICT_NUM(0);
    987 		ent->v.goalentity = EDICT_TO_PROG(tent);
    988 		return;
    989 	}
    990 	host_client->spec_track = i + 1; // now tracking
    991 
    992 	ent = EDICT_NUM(host_client - svs.clients + 1);
    993 	tent = EDICT_NUM(i + 1);
    994 	ent->v.goalentity = EDICT_TO_PROG(tent);
    995 }
    996 
    997 
    998 /*
    999 =================
   1000 SV_Rate_f
   1001 
   1002 Change the bandwidth estimate for a client
   1003 =================
   1004 */
   1005 void SV_Rate_f (void)
   1006 {
   1007 	int		rate;
   1008 
   1009 	if (Cmd_Argc() != 2)
   1010 	{
   1011 		SV_ClientPrintf (host_client, PRINT_HIGH, "Current rate is %i\n",
   1012 			(int)(1.0/host_client->netchan.rate + 0.5));
   1013 		return;
   1014 	}
   1015 
   1016 	rate = atoi(Cmd_Argv(1));
   1017 	if (rate < 500)
   1018 		rate = 500;
   1019 	if (rate > 10000)
   1020 		rate = 10000;
   1021 
   1022 	SV_ClientPrintf (host_client, PRINT_HIGH, "Net rate set to %i\n", rate);
   1023 	host_client->netchan.rate = 1.0/rate;
   1024 }
   1025 
   1026 
   1027 /*
   1028 =================
   1029 SV_Msg_f
   1030 
   1031 Change the message level for a client
   1032 =================
   1033 */
   1034 void SV_Msg_f (void)
   1035 {
   1036 	if (Cmd_Argc() != 2)
   1037 	{
   1038 		SV_ClientPrintf (host_client, PRINT_HIGH, "Current msg level is %i\n",
   1039 			host_client->messagelevel);
   1040 		return;
   1041 	}
   1042 
   1043 	host_client->messagelevel = atoi(Cmd_Argv(1));
   1044 
   1045 	SV_ClientPrintf (host_client, PRINT_HIGH, "Msg level set to %i\n", host_client->messagelevel);
   1046 }
   1047 
   1048 /*
   1049 ==================
   1050 SV_SetInfo_f
   1051 
   1052 Allow clients to change userinfo
   1053 ==================
   1054 */
   1055 void SV_SetInfo_f (void)
   1056 {
   1057 	int i;
   1058 	char oldval[MAX_INFO_STRING];
   1059 
   1060 
   1061 	if (Cmd_Argc() == 1)
   1062 	{
   1063 		Con_Printf ("User info settings:\n");
   1064 		Info_Print (host_client->userinfo);
   1065 		return;
   1066 	}
   1067 
   1068 	if (Cmd_Argc() != 3)
   1069 	{
   1070 		Con_Printf ("usage: setinfo [ <key> <value> ]\n");
   1071 		return;
   1072 	}
   1073 
   1074 	if (Cmd_Argv(1)[0] == '*')
   1075 		return;		// don't set priveledged values
   1076 
   1077 	strcpy(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
   1078 
   1079 	Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING);
   1080 // name is extracted below in ExtractFromUserInfo
   1081 //	strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name")
   1082 //		, sizeof(host_client->name)-1);
   1083 //	SV_FullClientUpdate (host_client, &sv.reliable_datagram);
   1084 //	host_client->sendinfo = true;
   1085 
   1086 	if (!strcmp(Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)), oldval))
   1087 		return; // key hasn't changed
   1088 
   1089 	// process any changed values
   1090 	SV_ExtractFromUserinfo (host_client);
   1091 
   1092 	i = host_client - svs.clients;
   1093 	MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
   1094 	MSG_WriteByte (&sv.reliable_datagram, i);
   1095 	MSG_WriteString (&sv.reliable_datagram, Cmd_Argv(1));
   1096 	MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
   1097 }
   1098 
   1099 /*
   1100 ==================
   1101 SV_ShowServerinfo_f
   1102 
   1103 Dumps the serverinfo info string
   1104 ==================
   1105 */
   1106 void SV_ShowServerinfo_f (void)
   1107 {
   1108 	Info_Print (svs.info);
   1109 }
   1110 
   1111 void SV_NoSnap_f(void)
   1112 {
   1113 	if (*host_client->uploadfn) {
   1114 		*host_client->uploadfn = 0;
   1115 		SV_BroadcastPrintf (PRINT_HIGH, "%s refused remote screenshot\n", host_client->name);
   1116 	}
   1117 }
   1118 
   1119 typedef struct
   1120 {
   1121 	char	*name;
   1122 	void	(*func) (void);
   1123 } ucmd_t;
   1124 
   1125 ucmd_t ucmds[] =
   1126 {
   1127 	{"new", SV_New_f},
   1128 	{"modellist", SV_Modellist_f},
   1129 	{"soundlist", SV_Soundlist_f},
   1130 	{"prespawn", SV_PreSpawn_f},
   1131 	{"spawn", SV_Spawn_f},
   1132 	{"begin", SV_Begin_f},
   1133 
   1134 	{"drop", SV_Drop_f},
   1135 	{"pings", SV_Pings_f},
   1136 
   1137 // issued by hand at client consoles
   1138 	{"rate", SV_Rate_f},
   1139 	{"kill", SV_Kill_f},
   1140 	{"pause", SV_Pause_f},
   1141 	{"msg", SV_Msg_f},
   1142 
   1143 	{"say", SV_Say_f},
   1144 	{"say_team", SV_Say_Team_f},
   1145 
   1146 	{"setinfo", SV_SetInfo_f},
   1147 
   1148 	{"serverinfo", SV_ShowServerinfo_f},
   1149 
   1150 	{"download", SV_BeginDownload_f},
   1151 	{"nextdl", SV_NextDownload_f},
   1152 
   1153 	{"ptrack", SV_PTrack_f}, //ZOID - used with autocam
   1154 
   1155 	{"snap", SV_NoSnap_f},
   1156 
   1157 	{NULL, NULL}
   1158 };
   1159 
   1160 /*
   1161 ==================
   1162 SV_ExecuteUserCommand
   1163 ==================
   1164 */
   1165 void SV_ExecuteUserCommand (char *s)
   1166 {
   1167 	ucmd_t	*u;
   1168 
   1169 	Cmd_TokenizeString (s);
   1170 	sv_player = host_client->edict;
   1171 
   1172 	SV_BeginRedirect (RD_CLIENT);
   1173 
   1174 	for (u=ucmds ; u->name ; u++)
   1175 		if (!strcmp (Cmd_Argv(0), u->name) )
   1176 		{
   1177 			u->func ();
   1178 			break;
   1179 		}
   1180 
   1181 	if (!u->name)
   1182 		Con_Printf ("Bad user command: %s\n", Cmd_Argv(0));
   1183 
   1184 	SV_EndRedirect ();
   1185 }
   1186 
   1187 /*
   1188 ===========================================================================
   1189 
   1190 USER CMD EXECUTION
   1191 
   1192 ===========================================================================
   1193 */
   1194 
   1195 /*
   1196 ===============
   1197 V_CalcRoll
   1198 
   1199 Used by view and sv_user
   1200 ===============
   1201 */
   1202 float V_CalcRoll (vec3_t angles, vec3_t velocity)
   1203 {
   1204 	vec3_t	forward, right, up;
   1205 	float	sign;
   1206 	float	side;
   1207 	float	value;
   1208 
   1209 	AngleVectors (angles, forward, right, up);
   1210 	side = DotProduct (velocity, right);
   1211 	sign = side < 0 ? -1 : 1;
   1212 	side = fabs(side);
   1213 
   1214 	value = cl_rollangle.value;
   1215 
   1216 	if (side < cl_rollspeed.value)
   1217 		side = side * value / cl_rollspeed.value;
   1218 	else
   1219 		side = value;
   1220 
   1221 	return side*sign;
   1222 
   1223 }
   1224 
   1225 
   1226 
   1227 
   1228 //============================================================================
   1229 
   1230 vec3_t	pmove_mins, pmove_maxs;
   1231 
   1232 /*
   1233 ====================
   1234 AddLinksToPmove
   1235 
   1236 ====================
   1237 */
   1238 void AddLinksToPmove ( areanode_t *node )
   1239 {
   1240 	link_t		*l, *next;
   1241 	edict_t		*check;
   1242 	int			pl;
   1243 	int			i;
   1244 	physent_t	*pe;
   1245 
   1246 	pl = EDICT_TO_PROG(sv_player);
   1247 
   1248 	// touch linked edicts
   1249 	for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
   1250 	{
   1251 		next = l->next;
   1252 		check = EDICT_FROM_AREA(l);
   1253 
   1254 		if (check->v.owner == pl)
   1255 			continue;		// player's own missile
   1256 		if (check->v.solid == SOLID_BSP
   1257 			|| check->v.solid == SOLID_BBOX
   1258 			|| check->v.solid == SOLID_SLIDEBOX)
   1259 		{
   1260 			if (check == sv_player)
   1261 				continue;
   1262 
   1263 			for (i=0 ; i<3 ; i++)
   1264 				if (check->v.absmin[i] > pmove_maxs[i]
   1265 				|| check->v.absmax[i] < pmove_mins[i])
   1266 					break;
   1267 			if (i != 3)
   1268 				continue;
   1269 			if (pmove.numphysent == MAX_PHYSENTS)
   1270 				return;
   1271 			pe = &pmove.physents[pmove.numphysent];
   1272 			pmove.numphysent++;
   1273 
   1274 			VectorCopy (check->v.origin, pe->origin);
   1275 			pe->info = NUM_FOR_EDICT(check);
   1276 			if (check->v.solid == SOLID_BSP)
   1277 				pe->model = sv.models[(int)(check->v.modelindex)];
   1278 			else
   1279 			{
   1280 				pe->model = NULL;
   1281 				VectorCopy (check->v.mins, pe->mins);
   1282 				VectorCopy (check->v.maxs, pe->maxs);
   1283 			}
   1284 		}
   1285 	}
   1286 
   1287 // recurse down both sides
   1288 	if (node->axis == -1)
   1289 		return;
   1290 
   1291 	if ( pmove_maxs[node->axis] > node->dist )
   1292 		AddLinksToPmove ( node->children[0] );
   1293 	if ( pmove_mins[node->axis] < node->dist )
   1294 		AddLinksToPmove ( node->children[1] );
   1295 }
   1296 
   1297 
   1298 /*
   1299 ================
   1300 AddAllEntsToPmove
   1301 
   1302 For debugging
   1303 ================
   1304 */
   1305 void AddAllEntsToPmove (void)
   1306 {
   1307 	int			e;
   1308 	edict_t		*check;
   1309 	int			i;
   1310 	physent_t	*pe;
   1311 	int			pl;
   1312 
   1313 	pl = EDICT_TO_PROG(sv_player);
   1314 	check = NEXT_EDICT(sv.edicts);
   1315 	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
   1316 	{
   1317 		if (check->free)
   1318 			continue;
   1319 		if (check->v.owner == pl)
   1320 			continue;
   1321 		if (check->v.solid == SOLID_BSP
   1322 			|| check->v.solid == SOLID_BBOX
   1323 			|| check->v.solid == SOLID_SLIDEBOX)
   1324 		{
   1325 			if (check == sv_player)
   1326 				continue;
   1327 
   1328 			for (i=0 ; i<3 ; i++)
   1329 				if (check->v.absmin[i] > pmove_maxs[i]
   1330 				|| check->v.absmax[i] < pmove_mins[i])
   1331 					break;
   1332 			if (i != 3)
   1333 				continue;
   1334 			pe = &pmove.physents[pmove.numphysent];
   1335 
   1336 			VectorCopy (check->v.origin, pe->origin);
   1337 			pmove.physents[pmove.numphysent].info = e;
   1338 			if (check->v.solid == SOLID_BSP)
   1339 				pe->model = sv.models[(int)(check->v.modelindex)];
   1340 			else
   1341 			{
   1342 				pe->model = NULL;
   1343 				VectorCopy (check->v.mins, pe->mins);
   1344 				VectorCopy (check->v.maxs, pe->maxs);
   1345 			}
   1346 
   1347 			if (++pmove.numphysent == MAX_PHYSENTS)
   1348 				break;
   1349 		}
   1350 	}
   1351 }
   1352 
   1353 /*
   1354 ===========
   1355 SV_PreRunCmd
   1356 ===========
   1357 Done before running a player command.  Clears the touch array
   1358 */
   1359 byte playertouch[(MAX_EDICTS+7)/8];
   1360 
   1361 void SV_PreRunCmd(void)
   1362 {
   1363 	memset(playertouch, 0, sizeof(playertouch));
   1364 }
   1365 
   1366 /*
   1367 ===========
   1368 SV_RunCmd
   1369 ===========
   1370 */
   1371 void SV_RunCmd (usercmd_t *ucmd)
   1372 {
   1373 	edict_t		*ent;
   1374 	int			i, n;
   1375 	int			oldmsec;
   1376 
   1377 	cmd = *ucmd;
   1378 
   1379 	// chop up very long commands
   1380 	if (cmd.msec > 50)
   1381 	{
   1382 		oldmsec = ucmd->msec;
   1383 		cmd.msec = oldmsec/2;
   1384 		SV_RunCmd (&cmd);
   1385 		cmd.msec = oldmsec/2;
   1386 		cmd.impulse = 0;
   1387 		SV_RunCmd (&cmd);
   1388 		return;
   1389 	}
   1390 
   1391 	if (!sv_player->v.fixangle)
   1392 		VectorCopy (ucmd->angles, sv_player->v.v_angle);
   1393 
   1394 	sv_player->v.button0 = ucmd->buttons & 1;
   1395 	sv_player->v.button2 = (ucmd->buttons & 2)>>1;
   1396 	if (ucmd->impulse)
   1397 		sv_player->v.impulse = ucmd->impulse;
   1398 
   1399 //
   1400 // angles
   1401 // show 1/3 the pitch angle and all the roll angle
   1402 	if (sv_player->v.health > 0)
   1403 	{
   1404 		if (!sv_player->v.fixangle)
   1405 		{
   1406 			sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3;
   1407 			sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW];
   1408 		}
   1409 		sv_player->v.angles[ROLL] =
   1410 			V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
   1411 	}
   1412 
   1413 	host_frametime = ucmd->msec * 0.001;
   1414 	if (host_frametime > 0.1)
   1415 		host_frametime = 0.1;
   1416 
   1417 	if (!host_client->spectator)
   1418 	{
   1419 		pr_global_struct->frametime = host_frametime;
   1420 
   1421 		pr_global_struct->time = sv.time;
   1422 		pr_global_struct->self = EDICT_TO_PROG(sv_player);
   1423 		PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
   1424 
   1425 		SV_RunThink (sv_player);
   1426 	}
   1427 
   1428 	for (i=0 ; i<3 ; i++)
   1429 		pmove.origin[i] = sv_player->v.origin[i] + (sv_player->v.mins[i] - player_mins[i]);
   1430 	VectorCopy (sv_player->v.velocity, pmove.velocity);
   1431 	VectorCopy (sv_player->v.v_angle, pmove.angles);
   1432 
   1433 	pmove.spectator = host_client->spectator;
   1434 	pmove.waterjumptime = sv_player->v.teleport_time;
   1435 	pmove.numphysent = 1;
   1436 	pmove.physents[0].model = sv.worldmodel;
   1437 	pmove.cmd = *ucmd;
   1438 	pmove.dead = sv_player->v.health <= 0;
   1439 	pmove.oldbuttons = host_client->oldbuttons;
   1440 
   1441 	movevars.entgravity = host_client->entgravity;
   1442 	movevars.maxspeed = host_client->maxspeed;
   1443 
   1444 	for (i=0 ; i<3 ; i++)
   1445 	{
   1446 		pmove_mins[i] = pmove.origin[i] - 256;
   1447 		pmove_maxs[i] = pmove.origin[i] + 256;
   1448 	}
   1449 #if 1
   1450 	AddLinksToPmove ( sv_areanodes );
   1451 #else
   1452 	AddAllEntsToPmove ();
   1453 #endif
   1454 
   1455 #if 0
   1456 {
   1457 	int before, after;
   1458 
   1459 before = PM_TestPlayerPosition (pmove.origin);
   1460 	PlayerMove ();
   1461 after = PM_TestPlayerPosition (pmove.origin);
   1462 
   1463 if (sv_player->v.health > 0 && before && !after )
   1464 	Con_Printf ("player %s got stuck in playermove!!!!\n", host_client->name);
   1465 }
   1466 #else
   1467 	PlayerMove ();
   1468 #endif
   1469 
   1470 	host_client->oldbuttons = pmove.oldbuttons;
   1471 	sv_player->v.teleport_time = pmove.waterjumptime;
   1472 	sv_player->v.waterlevel = waterlevel;
   1473 	sv_player->v.watertype = watertype;
   1474 	if (onground != -1)
   1475 	{
   1476 		sv_player->v.flags = (int)sv_player->v.flags | FL_ONGROUND;
   1477 		sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[onground].info));
   1478 	}
   1479 	else
   1480 		sv_player->v.flags = (int)sv_player->v.flags & ~FL_ONGROUND;
   1481 	for (i=0 ; i<3 ; i++)
   1482 		sv_player->v.origin[i] = pmove.origin[i] - (sv_player->v.mins[i] - player_mins[i]);
   1483 
   1484 #if 0
   1485 	// truncate velocity the same way the net protocol will
   1486 	for (i=0 ; i<3 ; i++)
   1487 		sv_player->v.velocity[i] = (int)pmove.velocity[i];
   1488 #else
   1489 	VectorCopy (pmove.velocity, sv_player->v.velocity);
   1490 #endif
   1491 
   1492 	VectorCopy (pmove.angles, sv_player->v.v_angle);
   1493 
   1494 	if (!host_client->spectator)
   1495 	{
   1496 		// link into place and touch triggers
   1497 		SV_LinkEdict (sv_player, true);
   1498 
   1499 		// touch other objects
   1500 		for (i=0 ; i<pmove.numtouch ; i++)
   1501 		{
   1502 			n = pmove.physents[pmove.touchindex[i]].info;
   1503 			ent = EDICT_NUM(n);
   1504 			if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8))))
   1505 				continue;
   1506 			pr_global_struct->self = EDICT_TO_PROG(ent);
   1507 			pr_global_struct->other = EDICT_TO_PROG(sv_player);
   1508 			PR_ExecuteProgram (ent->v.touch);
   1509 			playertouch[n/8] |= 1 << (n%8);
   1510 		}
   1511 	}
   1512 }
   1513 
   1514 /*
   1515 ===========
   1516 SV_PostRunCmd
   1517 ===========
   1518 Done after running a player command.
   1519 */
   1520 void SV_PostRunCmd(void)
   1521 {
   1522 	// run post-think
   1523 
   1524 	if (!host_client->spectator) {
   1525 		pr_global_struct->time = sv.time;
   1526 		pr_global_struct->self = EDICT_TO_PROG(sv_player);
   1527 		PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
   1528 		SV_RunNewmis ();
   1529 	} else if (SpectatorThink) {
   1530 		pr_global_struct->time = sv.time;
   1531 		pr_global_struct->self = EDICT_TO_PROG(sv_player);
   1532 		PR_ExecuteProgram (SpectatorThink);
   1533 	}
   1534 }
   1535 
   1536 
   1537 /*
   1538 ===================
   1539 SV_ExecuteClientMessage
   1540 
   1541 The current net_message is parsed for the given client
   1542 ===================
   1543 */
   1544 void SV_ExecuteClientMessage (client_t *cl)
   1545 {
   1546 	int		c;
   1547 	char	*s;
   1548 	usercmd_t	oldest, oldcmd, newcmd;
   1549 	client_frame_t	*frame;
   1550 	vec3_t o;
   1551 	qboolean	move_issued = false; //only allow one move command
   1552 	int		checksumIndex;
   1553 	byte	checksum, calculatedChecksum;
   1554 	int		seq_hash;
   1555 
   1556 	// calc ping time
   1557 	frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
   1558 	frame->ping_time = realtime - frame->senttime;
   1559 
   1560 	// make sure the reply sequence number matches the incoming
   1561 	// sequence number
   1562 	if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence)
   1563 		cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence;
   1564 	else
   1565 		cl->send_message = false;	// don't reply, sequences have slipped
   1566 
   1567 	// save time for ping calculations
   1568 	cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
   1569 	cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;
   1570 
   1571 	host_client = cl;
   1572 	sv_player = host_client->edict;
   1573 
   1574 //	seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
   1575 	seq_hash = cl->netchan.incoming_sequence;
   1576 
   1577 	// mark time so clients will know how much to predict
   1578 	// other players
   1579  	cl->localtime = sv.time;
   1580 	cl->delta_sequence = -1;	// no delta unless requested
   1581 	while (1)
   1582 	{
   1583 		if (msg_badread)
   1584 		{
   1585 			Con_Printf ("SV_ReadClientMessage: badread\n");
   1586 			SV_DropClient (cl);
   1587 			return;
   1588 		}
   1589 
   1590 		c = MSG_ReadByte ();
   1591 		if (c == -1)
   1592 			break;
   1593 
   1594 		switch (c)
   1595 		{
   1596 		default:
   1597 			Con_Printf ("SV_ReadClientMessage: unknown command char\n");
   1598 			SV_DropClient (cl);
   1599 			return;
   1600 
   1601 		case clc_nop:
   1602 			break;
   1603 
   1604 		case clc_delta:
   1605 			cl->delta_sequence = MSG_ReadByte ();
   1606 			break;
   1607 
   1608 		case clc_move:
   1609 			if (move_issued)
   1610 				return;		// someone is trying to cheat...
   1611 
   1612 			move_issued = true;
   1613 
   1614 			checksumIndex = MSG_GetReadCount();
   1615 			checksum = (byte)MSG_ReadByte ();
   1616 
   1617 			// read loss percentage
   1618 			cl->lossage = MSG_ReadByte();
   1619 
   1620 			MSG_ReadDeltaUsercmd (&nullcmd, &oldest);
   1621 			MSG_ReadDeltaUsercmd (&oldest, &oldcmd);
   1622 			MSG_ReadDeltaUsercmd (&oldcmd, &newcmd);
   1623 
   1624 			if ( cl->state != cs_spawned )
   1625 				break;
   1626 
   1627 			// if the checksum fails, ignore the rest of the packet
   1628 			calculatedChecksum = COM_BlockSequenceCRCByte(
   1629 				net_message.data + checksumIndex + 1,
   1630 				MSG_GetReadCount() - checksumIndex - 1,
   1631 				seq_hash);
   1632 
   1633 			if (calculatedChecksum != checksum)
   1634 			{
   1635 				Con_DPrintf ("Failed command checksum for %s(%d) (%d != %d)\n",
   1636 					cl->name, cl->netchan.incoming_sequence, checksum, calculatedChecksum);
   1637 				return;
   1638 			}
   1639 
   1640 			if (!sv.paused) {
   1641 				SV_PreRunCmd();
   1642 
   1643 				if (net_drop < 20)
   1644 				{
   1645 					while (net_drop > 2)
   1646 					{
   1647 						SV_RunCmd (&cl->lastcmd);
   1648 						net_drop--;
   1649 					}
   1650 					if (net_drop > 1)
   1651 						SV_RunCmd (&oldest);
   1652 					if (net_drop > 0)
   1653 						SV_RunCmd (&oldcmd);
   1654 				}
   1655 				SV_RunCmd (&newcmd);
   1656 
   1657 				SV_PostRunCmd();
   1658 			}
   1659 
   1660 			cl->lastcmd = newcmd;
   1661 			cl->lastcmd.buttons = 0; // avoid multiple fires on lag
   1662 			break;
   1663 
   1664 
   1665 		case clc_stringcmd:
   1666 			s = MSG_ReadString ();
   1667 			SV_ExecuteUserCommand (s);
   1668 			break;
   1669 
   1670 		case clc_tmove:
   1671 			o[0] = MSG_ReadCoord();
   1672 			o[1] = MSG_ReadCoord();
   1673 			o[2] = MSG_ReadCoord();
   1674 			// only allowed by spectators
   1675 			if (host_client->spectator) {
   1676 				VectorCopy(o, sv_player->v.origin);
   1677 				SV_LinkEdict(sv_player, false);
   1678 			}
   1679 			break;
   1680 
   1681 		case clc_upload:
   1682 			SV_NextUpload();
   1683 			break;
   1684 
   1685 		}
   1686 	}
   1687 }
   1688 
   1689 /*
   1690 ==============
   1691 SV_UserInit
   1692 ==============
   1693 */
   1694 void SV_UserInit (void)
   1695 {
   1696 	Cvar_RegisterVariable (&cl_rollspeed);
   1697 	Cvar_RegisterVariable (&cl_rollangle);
   1698 	Cvar_RegisterVariable (&sv_spectalk);
   1699 	Cvar_RegisterVariable (&sv_mapcheck);
   1700 }
   1701 
   1702 
   1703