1999-12-25 05:22:39 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
2000-01-08 04:50:26 +00:00
Portions Copyright ( C ) 1999 , 2000 Nelson Rush .
2000-01-08 22:02:43 +00:00
Copyright ( C ) 1999 , 2000 contributors of the QuakeForge project
Please see the file " AUTHORS " for a list of contributors
1999-12-25 05:22:39 +00:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// sv_user.c -- server code for moving users
2000-02-11 04:55:11 +00:00
# include <ctype.h>
# include <quakedef.h>
# include <qtypes.h>
# include <net.h>
# include <cmd.h>
# include <sys.h>
# include <console.h>
# include <protocol.h>
# include <server.h>
# include <phys.h>
# include <mathlib.h>
# include <world.h>
1999-12-25 05:22:39 +00:00
edict_t * sv_player ;
usercmd_t cmd ;
cvar_t cl_rollspeed = { " cl_rollspeed " , " 200 " } ;
cvar_t cl_rollangle = { " cl_rollangle " , " 2.0 " } ;
cvar_t sv_spectalk = { " sv_spectalk " , " 1 " } ;
cvar_t sv_mapcheck = { " sv_mapcheck " , " 1 " } ;
extern vec3_t player_mins ;
extern int fp_messages , fp_persecond , fp_secondsdead ;
extern char fp_msg [ ] ;
extern cvar_t pausable ;
2000-01-15 22:52:56 +00:00
static int loss ;
1999-12-25 05:22:39 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
USER STRINGCMD EXECUTION
host_client and sv_player will be valid .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
SV_New_f
Sends the first message from the server to a connected client .
This will be sent on the initial connection and upon each server load .
= = = = = = = = = = = = = = = =
*/
void SV_New_f ( void )
{
char * gamedir ;
int playernum ;
if ( host_client - > state = = cs_spawned )
return ;
host_client - > state = cs_connected ;
host_client - > connection_started = realtime ;
// send the info about the new client to all connected clients
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true;
gamedir = Info_ValueForKey ( svs . info , " *gamedir " ) ;
if ( ! gamedir [ 0 ] )
gamedir = " qw " ;
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf ) {
Con_Printf ( " WARNING %s: [SV_New] Back buffered (%d0, clearing " , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
// send the serverdata
MSG_WriteByte ( & host_client - > netchan . message , svc_serverdata ) ;
MSG_WriteLong ( & host_client - > netchan . message , PROTOCOL_VERSION ) ;
MSG_WriteLong ( & host_client - > netchan . message , svs . spawncount ) ;
MSG_WriteString ( & host_client - > netchan . message , gamedir ) ;
playernum = NUM_FOR_EDICT ( host_client - > edict ) - 1 ;
if ( host_client - > spectator )
playernum | = 128 ;
MSG_WriteByte ( & host_client - > netchan . message , playernum ) ;
// send full levelname
MSG_WriteString ( & host_client - > netchan . message , PR_GetString ( sv . edicts - > v . message ) ) ;
// send the movevars
MSG_WriteFloat ( & host_client - > netchan . message , movevars . gravity ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . stopspeed ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . maxspeed ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . spectatormaxspeed ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . accelerate ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . airaccelerate ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . wateraccelerate ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . friction ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . waterfriction ) ;
MSG_WriteFloat ( & host_client - > netchan . message , movevars . entgravity ) ;
// send music
MSG_WriteByte ( & host_client - > netchan . message , svc_cdtrack ) ;
MSG_WriteByte ( & host_client - > netchan . message , sv . edicts - > v . sounds ) ;
// send server info string
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " fullserverinfo \" %s \" \n " , svs . info ) ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_Soundlist_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Soundlist_f ( void )
{
char * * s ;
int n ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " soundlist not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount )
{
Con_Printf ( " SV_Soundlist_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
n = atoi ( Cmd_Argv ( 2 ) ) ;
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf ) {
Con_Printf ( " WARNING %s: [SV_Soundlist] Back buffered (%d0, clearing " , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
MSG_WriteByte ( & host_client - > netchan . message , svc_soundlist ) ;
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
for ( s = sv . sound_precache + 1 + n ;
* s & & host_client - > netchan . message . cursize < ( MAX_MSGLEN / 2 ) ;
s + + , n + + )
MSG_WriteString ( & host_client - > netchan . message , * s ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
// next msg
if ( * s )
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_Modellist_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Modellist_f ( void )
{
char * * s ;
int n ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " modellist not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount )
{
Con_Printf ( " SV_Modellist_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
n = atoi ( Cmd_Argv ( 2 ) ) ;
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf ) {
Con_Printf ( " WARNING %s: [SV_Modellist] Back buffered (%d0, clearing " , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
MSG_WriteByte ( & host_client - > netchan . message , svc_modellist ) ;
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
for ( s = sv . model_precache + 1 + n ;
* s & & host_client - > netchan . message . cursize < ( MAX_MSGLEN / 2 ) ;
s + + , n + + )
MSG_WriteString ( & host_client - > netchan . message , * s ) ;
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
// next msg
if ( * s )
MSG_WriteByte ( & host_client - > netchan . message , n ) ;
else
MSG_WriteByte ( & host_client - > netchan . message , 0 ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_PreSpawn_f
= = = = = = = = = = = = = = = = = =
*/
void SV_PreSpawn_f ( void )
{
unsigned buf ;
unsigned check ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " prespawn not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount )
{
Con_Printf ( " SV_PreSpawn_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
buf = atoi ( Cmd_Argv ( 2 ) ) ;
if ( buf > = sv . num_signon_buffers )
buf = 0 ;
if ( ! buf ) {
// should be three numbers following containing checksums
check = atoi ( Cmd_Argv ( 3 ) ) ;
// Con_DPrintf("Client check = %d\n", check);
if ( sv_mapcheck . value & & check ! = sv . worldmodel - > checksum & &
check ! = sv . worldmodel - > checksum2 ) {
SV_ClientPrintf ( host_client , PRINT_HIGH ,
" Map model file does not match (%s), %i != %i/%i. \n "
" You may need a new version of the map, or the proper install files. \n " ,
sv . modelname , check , sv . worldmodel - > checksum , sv . worldmodel - > checksum2 ) ;
SV_DropClient ( host_client ) ;
return ;
}
host_client - > checksum = check ;
}
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
if ( host_client - > num_backbuf ) {
Con_Printf ( " WARNING %s: [SV_PreSpawn] Back buffered (%d0, clearing " , host_client - > name , host_client - > netchan . message . cursize ) ;
host_client - > num_backbuf = 0 ;
SZ_Clear ( & host_client - > netchan . message ) ;
}
SZ_Write ( & host_client - > netchan . message ,
sv . signon_buffers [ buf ] ,
sv . signon_buffer_size [ buf ] ) ;
buf + + ;
if ( buf = = sv . num_signon_buffers )
{ // all done prespawning
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message , va ( " cmd spawn %i 0 \n " , svs . spawncount ) ) ;
}
else
{ // need to prespawn more
MSG_WriteByte ( & host_client - > netchan . message , svc_stufftext ) ;
MSG_WriteString ( & host_client - > netchan . message ,
va ( " cmd prespawn %i %i \n " , svs . spawncount , buf ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Spawn_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Spawn_f ( void )
{
int i ;
client_t * client ;
edict_t * ent ;
eval_t * val ;
int n ;
if ( host_client - > state ! = cs_connected )
{
Con_Printf ( " Spawn not valid -- allready spawned \n " ) ;
return ;
}
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount )
{
Con_Printf ( " SV_Spawn_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
n = atoi ( Cmd_Argv ( 2 ) ) ;
// make sure n is valid
if ( n < 0 | | n > MAX_CLIENTS )
{
Con_Printf ( " SV_Spawn_f invalid client start \n " ) ;
SV_New_f ( ) ;
return ;
}
// send all current names, colors, and frag counts
// FIXME: is this a good thing?
SZ_Clear ( & host_client - > netchan . message ) ;
// send current status of all other players
// normally this could overflow, but no need to check due to backbuf
for ( i = n , client = svs . clients + n ; i < MAX_CLIENTS ; i + + , client + + )
SV_FullClientUpdateToClient ( client , host_client ) ;
// send all current light styles
for ( i = 0 ; i < MAX_LIGHTSTYLES ; i + + )
{
ClientReliableWrite_Begin ( host_client , svc_lightstyle ,
3 + ( sv . lightstyles [ i ] ? strlen ( sv . lightstyles [ i ] ) : 1 ) ) ;
ClientReliableWrite_Byte ( host_client , ( char ) i ) ;
ClientReliableWrite_String ( host_client , sv . lightstyles [ i ] ) ;
}
// set up the edict
ent = host_client - > edict ;
memset ( & ent - > v , 0 , progs - > entityfields * 4 ) ;
ent - > v . colormap = NUM_FOR_EDICT ( ent ) ;
ent - > v . team = 0 ; // FIXME
ent - > v . netname = PR_SetString ( host_client - > name ) ;
host_client - > entgravity = 1.0 ;
val = GetEdictFieldValue ( ent , " gravity " ) ;
if ( val )
val - > _float = 1.0 ;
host_client - > maxspeed = sv_maxspeed . value ;
val = GetEdictFieldValue ( ent , " maxspeed " ) ;
if ( val )
val - > _float = sv_maxspeed . value ;
//
// force stats to be updated
//
memset ( host_client - > stats , 0 , sizeof ( host_client - > stats ) ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_TOTALSECRETS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > total_secrets ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_TOTALMONSTERS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > total_monsters ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_SECRETS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > found_secrets ) ;
ClientReliableWrite_Begin ( host_client , svc_updatestatlong , 6 ) ;
ClientReliableWrite_Byte ( host_client , STAT_MONSTERS ) ;
ClientReliableWrite_Long ( host_client , pr_global_struct - > killed_monsters ) ;
// get the client to check and download skins
// when that is completed, a begin command will be issued
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " skins \n " ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_SpawnSpectator
= = = = = = = = = = = = = = = = = =
*/
void SV_SpawnSpectator ( void )
{
int i ;
edict_t * e ;
VectorCopy ( vec3_origin , sv_player - > v . origin ) ;
VectorCopy ( vec3_origin , sv_player - > v . view_ofs ) ;
sv_player - > v . view_ofs [ 2 ] = 22 ;
// search for an info_playerstart to spawn the spectator at
for ( i = MAX_CLIENTS - 1 ; i < sv . num_edicts ; i + + )
{
e = EDICT_NUM ( i ) ;
if ( ! strcmp ( PR_GetString ( e - > v . classname ) , " info_player_start " ) )
{
VectorCopy ( e - > v . origin , sv_player - > v . origin ) ;
return ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Begin_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Begin_f ( void )
{
unsigned pmodel = 0 , emodel = 0 ;
int i ;
if ( host_client - > state = = cs_spawned )
return ; // don't begin again
host_client - > state = cs_spawned ;
// handle the case of a level changing while a client was connecting
if ( atoi ( Cmd_Argv ( 1 ) ) ! = svs . spawncount )
{
Con_Printf ( " SV_Begin_f from different level \n " ) ;
SV_New_f ( ) ;
return ;
}
if ( host_client - > spectator )
{
SV_SpawnSpectator ( ) ;
if ( SpectatorConnect ) {
// copy spawn parms out of the client_t
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
( & pr_global_struct - > parm1 ) [ i ] = host_client - > spawn_parms [ i ] ;
// call the spawn function
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( sv_player ) ;
PR_ExecuteProgram ( SpectatorConnect ) ;
}
}
else
{
// copy spawn parms out of the client_t
for ( i = 0 ; i < NUM_SPAWN_PARMS ; i + + )
( & pr_global_struct - > parm1 ) [ i ] = host_client - > spawn_parms [ i ] ;
// call the spawn function
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( sv_player ) ;
PR_ExecuteProgram ( pr_global_struct - > ClientConnect ) ;
// actually spawn the player
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( sv_player ) ;
PR_ExecuteProgram ( pr_global_struct - > PutClientInServer ) ;
}
// clear the net statistics, because connecting gives a bogus picture
host_client - > netchan . frame_latency = 0 ;
host_client - > netchan . frame_rate = 0 ;
host_client - > netchan . drop_count = 0 ;
host_client - > netchan . good_count = 0 ;
//check he's not cheating
pmodel = atoi ( Info_ValueForKey ( host_client - > userinfo , " pmodel " ) ) ;
emodel = atoi ( Info_ValueForKey ( host_client - > userinfo , " emodel " ) ) ;
if ( pmodel ! = sv . model_player_checksum | |
emodel ! = sv . eyes_player_checksum )
SV_BroadcastPrintf ( PRINT_HIGH , " %s WARNING: non standard player/eyes model detected \n " , host_client - > name ) ;
// if we are paused, tell the client
if ( sv . paused ) {
ClientReliableWrite_Begin ( host_client , svc_setpause , 2 ) ;
ClientReliableWrite_Byte ( host_client , sv . paused ) ;
SV_ClientPrintf ( host_client , PRINT_HIGH , " Server is paused. \n " ) ;
}
#if 0
//
// send a fixangle over the reliable channel to make sure it gets there
// Never send a roll angle, because savegames can catch the server
// in a state where it is expecting the client to correct the angle
// and it won't happen if the game was just loaded, so you wind up
// with a permanent head tilt
ent = EDICT_NUM ( 1 + ( host_client - svs . clients ) ) ;
MSG_WriteByte ( & host_client - > netchan . message , svc_setangle ) ;
for ( i = 0 ; i < 2 ; i + + )
MSG_WriteAngle ( & host_client - > netchan . message , ent - > v . angles [ i ] ) ;
MSG_WriteAngle ( & host_client - > netchan . message , 0 ) ;
# endif
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = = =
SV_NextDownload_f
= = = = = = = = = = = = = = = = = =
*/
void SV_NextDownload_f ( void )
{
byte buffer [ 1024 ] ;
int r ;
int percent ;
int size ;
if ( ! host_client - > download )
return ;
r = host_client - > downloadsize - host_client - > downloadcount ;
if ( r > 768 )
r = 768 ;
2000-02-08 07:23:09 +00:00
r = Qread ( host_client - > download , buffer , r ) ;
1999-12-25 05:22:39 +00:00
ClientReliableWrite_Begin ( host_client , svc_download , 6 + r ) ;
ClientReliableWrite_Short ( host_client , r ) ;
host_client - > downloadcount + = r ;
size = host_client - > downloadsize ;
if ( ! size )
size = 1 ;
percent = host_client - > downloadcount * 100 / size ;
ClientReliableWrite_Byte ( host_client , percent ) ;
ClientReliableWrite_SZ ( host_client , buffer , r ) ;
if ( host_client - > downloadcount ! = host_client - > downloadsize )
return ;
2000-02-08 07:23:09 +00:00
Qclose ( host_client - > download ) ;
1999-12-25 05:22:39 +00:00
host_client - > download = NULL ;
}
void OutofBandPrintf ( netadr_t where , char * fmt , . . . )
{
va_list argptr ;
char send [ 1024 ] ;
send [ 0 ] = 0xff ;
send [ 1 ] = 0xff ;
send [ 2 ] = 0xff ;
send [ 3 ] = 0xff ;
send [ 4 ] = A2C_PRINT ;
va_start ( argptr , fmt ) ;
2000-01-08 13:55:33 +00:00
vsnprintf ( send + 5 , sizeof ( send ) - 5 , fmt , argptr ) ;
1999-12-25 05:22:39 +00:00
va_end ( argptr ) ;
NET_SendPacket ( strlen ( send ) + 1 , send , where ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_NextUpload
= = = = = = = = = = = = = = = = = =
*/
void SV_NextUpload ( void )
{
int percent ;
int size ;
if ( ! * host_client - > uploadfn ) {
SV_ClientPrintf ( host_client , PRINT_HIGH , " Upload denied \n " ) ;
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " stopul " ) ;
// suck out rest of packet
size = MSG_ReadShort ( ) ; MSG_ReadByte ( ) ;
msg_readcount + = size ;
return ;
}
size = MSG_ReadShort ( ) ;
percent = MSG_ReadByte ( ) ;
if ( ! host_client - > upload )
{
2000-02-08 07:23:09 +00:00
host_client - > upload = Qopen ( host_client - > uploadfn , " wb " ) ;
1999-12-25 05:22:39 +00:00
if ( ! host_client - > upload ) {
Sys_Printf ( " Can't create %s \n " , host_client - > uploadfn ) ;
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " stopul " ) ;
* host_client - > uploadfn = 0 ;
return ;
}
Sys_Printf ( " Receiving %s from %d... \n " , host_client - > uploadfn , host_client - > userid ) ;
if ( host_client - > remote_snap )
OutofBandPrintf ( host_client - > snap_from , " Server receiving %s from %d... \n " , host_client - > uploadfn , host_client - > userid ) ;
}
2000-02-08 07:23:09 +00:00
Qwrite ( host_client - > upload , net_message . data + msg_readcount , size ) ;
1999-12-25 05:22:39 +00:00
msg_readcount + = size ;
Con_DPrintf ( " UPLOAD: %d received \n " , size ) ;
if ( percent ! = 100 ) {
ClientReliableWrite_Begin ( host_client , svc_stufftext , 8 ) ;
ClientReliableWrite_String ( host_client , " nextul \n " ) ;
} else {
2000-02-08 07:23:09 +00:00
Qclose ( host_client - > upload ) ;
1999-12-25 05:22:39 +00:00
host_client - > upload = NULL ;
Sys_Printf ( " %s upload completed. \n " , host_client - > uploadfn ) ;
if ( host_client - > remote_snap ) {
char * p ;
if ( ( p = strchr ( host_client - > uploadfn , ' / ' ) ) ! = NULL )
p + + ;
else
p = host_client - > uploadfn ;
OutofBandPrintf ( host_client - > snap_from , " %s upload completed. \n To download, enter: \n download %s \n " ,
host_client - > uploadfn , p ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_BeginDownload_f
= = = = = = = = = = = = = = = = = =
*/
void SV_BeginDownload_f ( void )
{
char * name ;
extern cvar_t allow_download ;
extern cvar_t allow_download_skins ;
extern cvar_t allow_download_models ;
extern cvar_t allow_download_sounds ;
extern cvar_t allow_download_maps ;
extern int file_from_pak ; // ZOID did file come from pak?
name = Cmd_Argv ( 1 ) ;
// hacked by zoid to allow more conrol over download
// first off, no .. or global allow check
if ( strstr ( name , " .. " ) | | ! allow_download . value
// leading dot is no good
| | * name = = ' . '
// leading slash bad as well, must be in subdir
| | * name = = ' / '
// next up, skin check
| | ( strncmp ( name , " skins/ " , 6 ) = = 0 & & ! allow_download_skins . value )
// now models
| | ( strncmp ( name , " progs/ " , 6 ) = = 0 & & ! allow_download_models . value )
// now sounds
| | ( strncmp ( name , " sound/ " , 6 ) = = 0 & & ! allow_download_sounds . value )
// now maps (note special case for maps, must not be in pak)
| | ( strncmp ( name , " maps/ " , 6 ) = = 0 & & ! allow_download_maps . value )
// MUST be in a subdirectory
| | ! strstr ( name , " / " ) )
{ // don't allow anything with .. path
ClientReliableWrite_Begin ( host_client , svc_download , 4 ) ;
ClientReliableWrite_Short ( host_client , - 1 ) ;
ClientReliableWrite_Byte ( host_client , 0 ) ;
return ;
}
if ( host_client - > download ) {
2000-02-08 07:23:09 +00:00
Qclose ( host_client - > download ) ;
1999-12-25 05:22:39 +00:00
host_client - > download = NULL ;
}
// lowercase name (needed for casesen file systems)
{
char * p ;
for ( p = name ; * p ; p + + )
* p = ( char ) tolower ( * p ) ;
}
host_client - > downloadsize = COM_FOpenFile ( name , & host_client - > download ) ;
host_client - > downloadcount = 0 ;
if ( ! host_client - > download
// special check for maps, if it came from a pak file, don't allow
// download ZOID
| | ( strncmp ( name , " maps/ " , 5 ) = = 0 & & file_from_pak ) )
{
if ( host_client - > download ) {
2000-02-08 07:23:09 +00:00
Qclose ( host_client - > download ) ;
1999-12-25 05:22:39 +00:00
host_client - > download = NULL ;
}
Sys_Printf ( " Couldn't download %s to %s \n " , name , host_client - > name ) ;
ClientReliableWrite_Begin ( host_client , svc_download , 4 ) ;
ClientReliableWrite_Short ( host_client , - 1 ) ;
ClientReliableWrite_Byte ( host_client , 0 ) ;
return ;
}
SV_NextDownload_f ( ) ;
Sys_Printf ( " Downloading %s to %s \n " , name , host_client - > name ) ;
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = = =
SV_Say
= = = = = = = = = = = = = = = = = =
*/
void SV_Say ( qboolean team )
{
client_t * client ;
int j , tmp ;
char * p ;
char text [ 2048 ] ;
char t1 [ 32 ] , * t2 ;
if ( Cmd_Argc ( ) < 2 )
return ;
if ( team )
{
strncpy ( t1 , Info_ValueForKey ( host_client - > userinfo , " team " ) , 31 ) ;
t1 [ 31 ] = 0 ;
}
if ( host_client - > spectator & & ( ! sv_spectalk . value | | team ) )
2000-01-05 00:05:48 +00:00
snprintf ( text , sizeof ( text ) , " [SPEC] %s: " , host_client - > name ) ;
1999-12-25 05:22:39 +00:00
else if ( team )
2000-01-05 00:05:48 +00:00
snprintf ( text , sizeof ( text ) , " (%s): " , host_client - > name ) ;
1999-12-25 05:22:39 +00:00
else {
2000-01-05 00:05:48 +00:00
snprintf ( text , sizeof ( text ) , " %s: " , host_client - > name ) ;
1999-12-25 05:22:39 +00:00
}
if ( fp_messages ) {
if ( ! sv . paused & & realtime < host_client - > lockedtill ) {
SV_ClientPrintf ( host_client , PRINT_CHAT ,
" You can't talk for %d more seconds \n " ,
( int ) ( host_client - > lockedtill - realtime ) ) ;
return ;
}
tmp = host_client - > whensaidhead - fp_messages + 1 ;
if ( tmp < 0 )
tmp = 10 + tmp ;
if ( ! sv . paused & &
host_client - > whensaid [ tmp ] & & ( realtime - host_client - > whensaid [ tmp ] < fp_persecond ) ) {
host_client - > lockedtill = realtime + fp_secondsdead ;
if ( fp_msg [ 0 ] )
SV_ClientPrintf ( host_client , PRINT_CHAT ,
" FloodProt: %s \n " , fp_msg ) ;
else
SV_ClientPrintf ( host_client , PRINT_CHAT ,
" FloodProt: You can't talk for %d seconds. \n " , fp_secondsdead ) ;
return ;
}
host_client - > whensaidhead + + ;
if ( host_client - > whensaidhead > 9 )
host_client - > whensaidhead = 0 ;
host_client - > whensaid [ host_client - > whensaidhead ] = realtime ;
}
p = Cmd_Args ( ) ;
if ( * p = = ' " ' )
{
p + + ;
p [ Q_strlen ( p ) - 1 ] = 0 ;
}
Q_strcat ( text , p ) ;
Q_strcat ( text , " \n " ) ;
Sys_Printf ( " %s " , text ) ;
for ( j = 0 , client = svs . clients ; j < MAX_CLIENTS ; j + + , client + + )
{
if ( client - > state ! = cs_spawned )
continue ;
if ( host_client - > spectator & & ! sv_spectalk . value )
if ( ! client - > spectator )
continue ;
if ( team )
{
// the spectator team
if ( host_client - > spectator ) {
if ( ! client - > spectator )
continue ;
} else {
t2 = Info_ValueForKey ( client - > userinfo , " team " ) ;
if ( strcmp ( t1 , t2 ) | | client - > spectator )
continue ; // on different teams
}
}
SV_ClientPrintf ( client , PRINT_CHAT , " %s " , text ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Say_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Say_f ( void )
{
SV_Say ( false ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_Say_Team_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Say_Team_f ( void )
{
SV_Say ( true ) ;
}
//============================================================================
/*
= = = = = = = = = = = = = = = = =
SV_Pings_f
The client is showing the scoreboard , so send new ping times for all
clients
= = = = = = = = = = = = = = = = =
*/
void SV_Pings_f ( void )
{
client_t * client ;
int j ;
for ( j = 0 , client = svs . clients ; j < MAX_CLIENTS ; j + + , client + + )
{
if ( client - > state ! = cs_spawned )
continue ;
ClientReliableWrite_Begin ( host_client , svc_updateping , 4 ) ;
ClientReliableWrite_Byte ( host_client , j ) ;
2000-01-15 22:52:56 +00:00
ClientReliableWrite_Short ( host_client , client - > ping ) ;
1999-12-25 05:22:39 +00:00
ClientReliableWrite_Begin ( host_client , svc_updatepl , 4 ) ;
ClientReliableWrite_Byte ( host_client , j ) ;
ClientReliableWrite_Byte ( host_client , client - > lossage ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Kill_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Kill_f ( void )
{
if ( sv_player - > v . health < = 0 )
{
SV_ClientPrintf ( host_client , PRINT_HIGH , " Can't suicide -- allready dead! \n " ) ;
return ;
}
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( sv_player ) ;
PR_ExecuteProgram ( pr_global_struct - > ClientKill ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_TogglePause
= = = = = = = = = = = = = = = = = =
*/
void SV_TogglePause ( const char * msg )
{
int i ;
client_t * cl ;
sv . paused ^ = 1 ;
if ( msg )
SV_BroadcastPrintf ( PRINT_HIGH , " %s " , msg ) ;
// send notification to all clients
for ( i = 0 , cl = svs . clients ; i < MAX_CLIENTS ; i + + , cl + + )
{
if ( ! cl - > state )
continue ;
ClientReliableWrite_Begin ( cl , svc_setpause , 2 ) ;
ClientReliableWrite_Byte ( cl , sv . paused ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
SV_Pause_f
= = = = = = = = = = = = = = = = = =
*/
void SV_Pause_f ( void )
{
char st [ sizeof ( host_client - > name ) + 32 ] ;
if ( ! pausable . value ) {
SV_ClientPrintf ( host_client , PRINT_HIGH , " Pause not allowed. \n " ) ;
return ;
}
if ( host_client - > spectator ) {
SV_ClientPrintf ( host_client , PRINT_HIGH , " Spectators can not pause. \n " ) ;
return ;
}
if ( sv . paused )
2000-01-05 00:05:48 +00:00
snprintf ( st , sizeof ( st ) , " %s paused the game \n " , host_client - > name ) ;
1999-12-25 05:22:39 +00:00
else
2000-01-05 00:05:48 +00:00
snprintf ( st , sizeof ( st ) , " %s unpaused the game \n " , host_client - > name ) ;
1999-12-25 05:22:39 +00:00
SV_TogglePause ( st ) ;
}
/*
= = = = = = = = = = = = = = = = =
SV_Drop_f
The client is going to disconnect , so remove the connection immediately
= = = = = = = = = = = = = = = = =
*/
void SV_Drop_f ( void )
{
SV_EndRedirect ( ) ;
if ( ! host_client - > spectator )
SV_BroadcastPrintf ( PRINT_HIGH , " %s dropped \n " , host_client - > name ) ;
SV_DropClient ( host_client ) ;
}
/*
= = = = = = = = = = = = = = = = =
SV_PTrack_f
Change the bandwidth estimate for a client
= = = = = = = = = = = = = = = = =
*/
void SV_PTrack_f ( void )
{
int i ;
edict_t * ent , * tent ;
if ( ! host_client - > spectator )
return ;
if ( Cmd_Argc ( ) ! = 2 )
{
// turn off tracking
host_client - > spec_track = 0 ;
ent = EDICT_NUM ( host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( 0 ) ;
ent - > v . goalentity = EDICT_TO_PROG ( tent ) ;
return ;
}
i = atoi ( Cmd_Argv ( 1 ) ) ;
if ( i < 0 | | i > = MAX_CLIENTS | | svs . clients [ i ] . state ! = cs_spawned | |
svs . clients [ i ] . spectator ) {
SV_ClientPrintf ( host_client , PRINT_HIGH , " Invalid client to track \n " ) ;
host_client - > spec_track = 0 ;
ent = EDICT_NUM ( host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( 0 ) ;
ent - > v . goalentity = EDICT_TO_PROG ( tent ) ;
return ;
}
host_client - > spec_track = i + 1 ; // now tracking
ent = EDICT_NUM ( host_client - svs . clients + 1 ) ;
tent = EDICT_NUM ( i + 1 ) ;
ent - > v . goalentity = EDICT_TO_PROG ( tent ) ;
}
/*
= = = = = = = = = = = = = = = = =
SV_Rate_f
Change the bandwidth estimate for a client
= = = = = = = = = = = = = = = = =
*/
void SV_Rate_f ( void )
{
int rate ;
if ( Cmd_Argc ( ) ! = 2 )
{
SV_ClientPrintf ( host_client , PRINT_HIGH , " Current rate is %i \n " ,
( int ) ( 1.0 / host_client - > netchan . rate + 0.5 ) ) ;
return ;
}
rate = atoi ( Cmd_Argv ( 1 ) ) ;
if ( rate < 500 )
rate = 500 ;
if ( rate > 10000 )
rate = 10000 ;
SV_ClientPrintf ( host_client , PRINT_HIGH , " Net rate set to %i \n " , rate ) ;
host_client - > netchan . rate = 1.0 / rate ;
}
/*
= = = = = = = = = = = = = = = = =
SV_Msg_f
Change the message level for a client
= = = = = = = = = = = = = = = = =
*/
void SV_Msg_f ( void )
{
if ( Cmd_Argc ( ) ! = 2 )
{
SV_ClientPrintf ( host_client , PRINT_HIGH , " Current msg level is %i \n " ,
host_client - > messagelevel ) ;
return ;
}
host_client - > messagelevel = atoi ( Cmd_Argv ( 1 ) ) ;
SV_ClientPrintf ( host_client , PRINT_HIGH , " Msg level set to %i \n " , host_client - > messagelevel ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_SetInfo_f
Allow clients to change userinfo
= = = = = = = = = = = = = = = = = =
*/
void SV_SetInfo_f ( void )
{
int i ;
char oldval [ MAX_INFO_STRING ] ;
if ( Cmd_Argc ( ) = = 1 )
{
Con_Printf ( " User info settings: \n " ) ;
Info_Print ( host_client - > userinfo ) ;
return ;
}
if ( Cmd_Argc ( ) ! = 3 )
{
Con_Printf ( " usage: setinfo [ <key> <value> ] \n " ) ;
return ;
}
if ( Cmd_Argv ( 1 ) [ 0 ] = = ' * ' )
return ; // don't set priveledged values
strcpy ( oldval , Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) ) ;
Info_SetValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) , Cmd_Argv ( 2 ) , MAX_INFO_STRING ) ;
// name is extracted below in ExtractFromUserInfo
// strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name")
// , sizeof(host_client->name)-1);
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true;
if ( ! strcmp ( Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) , oldval ) )
return ; // key hasn't changed
// process any changed values
SV_ExtractFromUserinfo ( host_client ) ;
i = host_client - svs . clients ;
MSG_WriteByte ( & sv . reliable_datagram , svc_setinfo ) ;
MSG_WriteByte ( & sv . reliable_datagram , i ) ;
MSG_WriteString ( & sv . reliable_datagram , Cmd_Argv ( 1 ) ) ;
MSG_WriteString ( & sv . reliable_datagram , Info_ValueForKey ( host_client - > userinfo , Cmd_Argv ( 1 ) ) ) ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_ShowServerinfo_f
Dumps the serverinfo info string
= = = = = = = = = = = = = = = = = =
*/
void SV_ShowServerinfo_f ( void )
{
Info_Print ( svs . info ) ;
}
void SV_NoSnap_f ( void )
{
if ( * host_client - > uploadfn ) {
* host_client - > uploadfn = 0 ;
SV_BroadcastPrintf ( PRINT_HIGH , " %s refused remote screenshot \n " , host_client - > name ) ;
}
}
typedef struct
{
char * name ;
void ( * func ) ( void ) ;
} ucmd_t ;
ucmd_t ucmds [ ] =
{
{ " new " , SV_New_f } ,
{ " modellist " , SV_Modellist_f } ,
{ " soundlist " , SV_Soundlist_f } ,
{ " prespawn " , SV_PreSpawn_f } ,
{ " spawn " , SV_Spawn_f } ,
{ " begin " , SV_Begin_f } ,
{ " drop " , SV_Drop_f } ,
{ " pings " , SV_Pings_f } ,
// issued by hand at client consoles
{ " rate " , SV_Rate_f } ,
{ " kill " , SV_Kill_f } ,
{ " pause " , SV_Pause_f } ,
{ " msg " , SV_Msg_f } ,
{ " say " , SV_Say_f } ,
{ " say_team " , SV_Say_Team_f } ,
{ " setinfo " , SV_SetInfo_f } ,
{ " serverinfo " , SV_ShowServerinfo_f } ,
{ " download " , SV_BeginDownload_f } ,
{ " nextdl " , SV_NextDownload_f } ,
{ " ptrack " , SV_PTrack_f } , //ZOID - used with autocam
{ " snap " , SV_NoSnap_f } ,
{ NULL , NULL }
} ;
/*
= = = = = = = = = = = = = = = = = =
SV_ExecuteUserCommand
= = = = = = = = = = = = = = = = = =
*/
void SV_ExecuteUserCommand ( char * s )
{
ucmd_t * u ;
Cmd_TokenizeString ( s ) ;
sv_player = host_client - > edict ;
SV_BeginRedirect ( RD_CLIENT ) ;
for ( u = ucmds ; u - > name ; u + + )
if ( ! strcmp ( Cmd_Argv ( 0 ) , u - > name ) )
{
u - > func ( ) ;
break ;
}
if ( ! u - > name )
Con_Printf ( " Bad user command: %s \n " , Cmd_Argv ( 0 ) ) ;
SV_EndRedirect ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
USER CMD EXECUTION
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = =
V_CalcRoll
Used by view and sv_user
= = = = = = = = = = = = = = =
*/
float V_CalcRoll ( vec3_t angles , vec3_t velocity )
{
vec3_t forward , right , up ;
float sign ;
float side ;
float value ;
AngleVectors ( angles , forward , right , up ) ;
side = DotProduct ( velocity , right ) ;
sign = side < 0 ? - 1 : 1 ;
side = fabs ( side ) ;
value = cl_rollangle . value ;
if ( side < cl_rollspeed . value )
side = side * value / cl_rollspeed . value ;
else
side = value ;
return side * sign ;
}
//============================================================================
vec3_t pmove_mins , pmove_maxs ;
/*
= = = = = = = = = = = = = = = = = = = =
AddLinksToPmove
= = = = = = = = = = = = = = = = = = = =
*/
void AddLinksToPmove ( areanode_t * node )
{
link_t * l , * next ;
edict_t * check ;
int pl ;
int i ;
physent_t * pe ;
pl = EDICT_TO_PROG ( sv_player ) ;
// touch linked edicts
for ( l = node - > solid_edicts . next ; l ! = & node - > solid_edicts ; l = next )
{
next = l - > next ;
check = EDICT_FROM_AREA ( l ) ;
if ( check - > v . owner = = pl )
continue ; // player's own missile
if ( check - > v . solid = = SOLID_BSP
| | check - > v . solid = = SOLID_BBOX
| | check - > v . solid = = SOLID_SLIDEBOX )
{
if ( check = = sv_player )
continue ;
for ( i = 0 ; i < 3 ; i + + )
if ( check - > v . absmin [ i ] > pmove_maxs [ i ]
| | check - > v . absmax [ i ] < pmove_mins [ i ] )
break ;
if ( i ! = 3 )
continue ;
if ( pmove . numphysent = = MAX_PHYSENTS )
return ;
pe = & pmove . physents [ pmove . numphysent ] ;
pmove . numphysent + + ;
VectorCopy ( check - > v . origin , pe - > origin ) ;
pe - > info = NUM_FOR_EDICT ( check ) ;
if ( check - > v . solid = = SOLID_BSP )
pe - > model = sv . models [ ( int ) ( check - > v . modelindex ) ] ;
else
{
pe - > model = NULL ;
VectorCopy ( check - > v . mins , pe - > mins ) ;
VectorCopy ( check - > v . maxs , pe - > maxs ) ;
}
}
}
// recurse down both sides
if ( node - > axis = = - 1 )
return ;
if ( pmove_maxs [ node - > axis ] > node - > dist )
AddLinksToPmove ( node - > children [ 0 ] ) ;
if ( pmove_mins [ node - > axis ] < node - > dist )
AddLinksToPmove ( node - > children [ 1 ] ) ;
}
/*
= = = = = = = = = = = = = = = =
AddAllEntsToPmove
For debugging
= = = = = = = = = = = = = = = =
*/
void AddAllEntsToPmove ( void )
{
int e ;
edict_t * check ;
int i ;
physent_t * pe ;
int pl ;
pl = EDICT_TO_PROG ( sv_player ) ;
check = NEXT_EDICT ( sv . edicts ) ;
for ( e = 1 ; e < sv . num_edicts ; e + + , check = NEXT_EDICT ( check ) )
{
if ( check - > free )
continue ;
if ( check - > v . owner = = pl )
continue ;
if ( check - > v . solid = = SOLID_BSP
| | check - > v . solid = = SOLID_BBOX
| | check - > v . solid = = SOLID_SLIDEBOX )
{
if ( check = = sv_player )
continue ;
for ( i = 0 ; i < 3 ; i + + )
if ( check - > v . absmin [ i ] > pmove_maxs [ i ]
| | check - > v . absmax [ i ] < pmove_mins [ i ] )
break ;
if ( i ! = 3 )
continue ;
pe = & pmove . physents [ pmove . numphysent ] ;
VectorCopy ( check - > v . origin , pe - > origin ) ;
pmove . physents [ pmove . numphysent ] . info = e ;
if ( check - > v . solid = = SOLID_BSP )
pe - > model = sv . models [ ( int ) ( check - > v . modelindex ) ] ;
else
{
pe - > model = NULL ;
VectorCopy ( check - > v . mins , pe - > mins ) ;
VectorCopy ( check - > v . maxs , pe - > maxs ) ;
}
if ( + + pmove . numphysent = = MAX_PHYSENTS )
break ;
}
}
}
/*
= = = = = = = = = = =
SV_PreRunCmd
= = = = = = = = = = =
Done before running a player command . Clears the touch array
*/
byte playertouch [ ( MAX_EDICTS + 7 ) / 8 ] ;
void SV_PreRunCmd ( void )
{
memset ( playertouch , 0 , sizeof ( playertouch ) ) ;
}
2000-01-05 22:41:36 +00:00
2000-02-23 19:32:54 +00:00
// Over how long do we make the checks?
# define CHECK_TIME 30
2000-01-17 17:19:01 +00:00
2000-02-23 19:32:54 +00:00
// How many failed checks before we boot the guy?
# define CHECK_LIMIT 3
2000-01-17 17:19:01 +00:00
1999-12-25 05:22:39 +00:00
/*
= = = = = = = = = = =
SV_RunCmd
= = = = = = = = = = =
*/
2000-01-07 05:04:18 +00:00
void SV_RunCmd ( usercmd_t * ucmd , qboolean inside )
1999-12-25 05:22:39 +00:00
{
2000-01-15 22:52:56 +00:00
edict_t * ent ;
2000-01-19 16:35:26 +00:00
int i , n , oldmsec ;
2000-01-15 22:52:56 +00:00
double tmp_time ;
1999-12-25 05:22:39 +00:00
2000-01-17 17:19:01 +00:00
// To prevent a infinite loop
2000-01-07 05:04:18 +00:00
if ( ! inside ) {
2000-01-19 16:35:26 +00:00
host_client - > msecs + = ucmd - > msec ;
if ( ( tmp_time = realtime - host_client - > last_check ) > = CHECK_TIME ) {
2000-02-23 19:32:54 +00:00
tmp_time * = 1010 ;
2000-01-19 22:51:34 +00:00
if ( host_client - > msecs > ( int ) ( tmp_time + 0.5 ) ) {
2000-01-19 16:35:26 +00:00
host_client - > msec_cheating + + ;
SV_BroadcastPrintf ( PRINT_HIGH ,
2000-02-23 19:32:54 +00:00
va ( " %s thinks %d msecs pass in %f msecs. (Strike %d/%d) \n "
host_client - > name , host_client - > msecs , tmp_time ,
host_client - > msec_cheating , CHECK_LIMIT ) ) ;
2000-01-19 16:35:26 +00:00
2000-02-23 19:32:54 +00:00
if ( host_client - > msec_cheating > = CHECK_LIMIT ) {
2000-01-19 16:35:26 +00:00
SV_BroadcastPrintf ( PRINT_HIGH ,
2000-02-23 19:32:54 +00:00
va ( " Strike %d for %s!! \n " ,
host_client - > msec_cheating , host_client - > name ) ) ;
SV_BroadcastPrintf ( PRINT_HIGH , " Please see http://www.quakeforge.net/speed_cheat.html for infomation on the cheat detection, and to explain how some may be cheating without knowing it. \n " ) ;
2000-01-19 16:35:26 +00:00
SV_DropClient ( host_client ) ;
}
}
2000-01-18 03:13:38 +00:00
2000-01-19 16:35:26 +00:00
host_client - > msecs = 0 ;
host_client - > last_check = realtime ;
2000-01-17 17:19:01 +00:00
}
2000-01-09 04:22:57 +00:00
}
2000-01-07 05:04:18 +00:00
2000-01-09 04:22:57 +00:00
cmd = * ucmd ;
2000-01-07 05:04:18 +00:00
2000-01-09 04:22:57 +00:00
// chop up very long commands
if ( cmd . msec > 50 ) {
oldmsec = ucmd - > msec ;
cmd . msec = oldmsec / 2 ;
SV_RunCmd ( & cmd , 1 ) ;
cmd . msec = oldmsec / 2 ;
cmd . impulse = 0 ;
SV_RunCmd ( & cmd , 1 ) ;
return ;
1999-12-25 05:22:39 +00:00
}
if ( ! sv_player - > v . fixangle )
VectorCopy ( ucmd - > angles , sv_player - > v . v_angle ) ;
sv_player - > v . button0 = ucmd - > buttons & 1 ;
sv_player - > v . button2 = ( ucmd - > buttons & 2 ) > > 1 ;
if ( ucmd - > impulse )
sv_player - > v . impulse = ucmd - > impulse ;
//
// angles
// show 1/3 the pitch angle and all the roll angle
if ( sv_player - > v . health > 0 )
{
if ( ! sv_player - > v . fixangle )
{
sv_player - > v . angles [ PITCH ] = - sv_player - > v . v_angle [ PITCH ] / 3 ;
sv_player - > v . angles [ YAW ] = sv_player - > v . v_angle [ YAW ] ;
}
sv_player - > v . angles [ ROLL ] =
V_CalcRoll ( sv_player - > v . angles , sv_player - > v . velocity ) * 4 ;
}
host_frametime = ucmd - > msec * 0.001 ;
if ( host_frametime > 0.1 )
host_frametime = 0.1 ;
if ( ! host_client - > spectator )
{
pr_global_struct - > frametime = host_frametime ;
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( sv_player ) ;
PR_ExecuteProgram ( pr_global_struct - > PlayerPreThink ) ;
SV_RunThink ( sv_player ) ;
}
for ( i = 0 ; i < 3 ; i + + )
pmove . origin [ i ] = sv_player - > v . origin [ i ] + ( sv_player - > v . mins [ i ] - player_mins [ i ] ) ;
VectorCopy ( sv_player - > v . velocity , pmove . velocity ) ;
VectorCopy ( sv_player - > v . v_angle , pmove . angles ) ;
pmove . spectator = host_client - > spectator ;
pmove . waterjumptime = sv_player - > v . teleport_time ;
pmove . numphysent = 1 ;
pmove . physents [ 0 ] . model = sv . worldmodel ;
pmove . cmd = * ucmd ;
pmove . dead = sv_player - > v . health < = 0 ;
pmove . oldbuttons = host_client - > oldbuttons ;
movevars . entgravity = host_client - > entgravity ;
movevars . maxspeed = host_client - > maxspeed ;
for ( i = 0 ; i < 3 ; i + + )
{
pmove_mins [ i ] = pmove . origin [ i ] - 256 ;
pmove_maxs [ i ] = pmove . origin [ i ] + 256 ;
}
# if 1
AddLinksToPmove ( sv_areanodes ) ;
# else
AddAllEntsToPmove ( ) ;
# endif
#if 0
{
int before , after ;
before = PM_TestPlayerPosition ( pmove . origin ) ;
PlayerMove ( ) ;
after = PM_TestPlayerPosition ( pmove . origin ) ;
if ( sv_player - > v . health > 0 & & before & & ! after )
Con_Printf ( " player %s got stuck in playermove!!!! \n " , host_client - > name ) ;
}
# else
PlayerMove ( ) ;
# endif
host_client - > oldbuttons = pmove . oldbuttons ;
sv_player - > v . teleport_time = pmove . waterjumptime ;
sv_player - > v . waterlevel = waterlevel ;
sv_player - > v . watertype = watertype ;
if ( onground ! = - 1 )
{
sv_player - > v . flags = ( int ) sv_player - > v . flags | FL_ONGROUND ;
sv_player - > v . groundentity = EDICT_TO_PROG ( EDICT_NUM ( pmove . physents [ onground ] . info ) ) ;
}
else
sv_player - > v . flags = ( int ) sv_player - > v . flags & ~ FL_ONGROUND ;
for ( i = 0 ; i < 3 ; i + + )
sv_player - > v . origin [ i ] = pmove . origin [ i ] - ( sv_player - > v . mins [ i ] - player_mins [ i ] ) ;
#if 0
// truncate velocity the same way the net protocol will
for ( i = 0 ; i < 3 ; i + + )
sv_player - > v . velocity [ i ] = ( int ) pmove . velocity [ i ] ;
# else
VectorCopy ( pmove . velocity , sv_player - > v . velocity ) ;
# endif
VectorCopy ( pmove . angles , sv_player - > v . v_angle ) ;
if ( ! host_client - > spectator )
{
// link into place and touch triggers
SV_LinkEdict ( sv_player , true ) ;
// touch other objects
for ( i = 0 ; i < pmove . numtouch ; i + + )
{
n = pmove . physents [ pmove . touchindex [ i ] ] . info ;
ent = EDICT_NUM ( n ) ;
if ( ! ent - > v . touch | | ( playertouch [ n / 8 ] & ( 1 < < ( n % 8 ) ) ) )
continue ;
pr_global_struct - > self = EDICT_TO_PROG ( ent ) ;
pr_global_struct - > other = EDICT_TO_PROG ( sv_player ) ;
PR_ExecuteProgram ( ent - > v . touch ) ;
playertouch [ n / 8 ] | = 1 < < ( n % 8 ) ;
}
}
}
/*
= = = = = = = = = = =
SV_PostRunCmd
= = = = = = = = = = =
Done after running a player command .
*/
void SV_PostRunCmd ( void )
{
// run post-think
if ( ! host_client - > spectator ) {
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( sv_player ) ;
PR_ExecuteProgram ( pr_global_struct - > PlayerPostThink ) ;
SV_RunNewmis ( ) ;
} else if ( SpectatorThink ) {
pr_global_struct - > time = sv . time ;
pr_global_struct - > self = EDICT_TO_PROG ( sv_player ) ;
PR_ExecuteProgram ( SpectatorThink ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
SV_ExecuteClientMessage
The current net_message is parsed for the given client
= = = = = = = = = = = = = = = = = = =
*/
void SV_ExecuteClientMessage ( client_t * cl )
{
int c ;
char * s ;
usercmd_t oldest , oldcmd , newcmd ;
client_frame_t * frame ;
vec3_t o ;
qboolean move_issued = false ; //only allow one move command
int checksumIndex ;
byte checksum , calculatedChecksum ;
int seq_hash ;
// calc ping time
frame = & cl - > frames [ cl - > netchan . incoming_acknowledged & UPDATE_MASK ] ;
frame - > ping_time = realtime - frame - > senttime ;
// make sure the reply sequence number matches the incoming
// sequence number
if ( cl - > netchan . incoming_sequence > = cl - > netchan . outgoing_sequence )
cl - > netchan . outgoing_sequence = cl - > netchan . incoming_sequence ;
else
cl - > send_message = false ; // don't reply, sequences have slipped
// save time for ping calculations
cl - > frames [ cl - > netchan . outgoing_sequence & UPDATE_MASK ] . senttime = realtime ;
cl - > frames [ cl - > netchan . outgoing_sequence & UPDATE_MASK ] . ping_time = - 1 ;
host_client = cl ;
sv_player = host_client - > edict ;
// seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
seq_hash = cl - > netchan . incoming_sequence ;
// mark time so clients will know how much to predict
// other players
cl - > localtime = sv . time ;
cl - > delta_sequence = - 1 ; // no delta unless requested
while ( 1 )
{
if ( msg_badread )
{
Con_Printf ( " SV_ReadClientMessage: badread \n " ) ;
SV_DropClient ( cl ) ;
return ;
}
c = MSG_ReadByte ( ) ;
if ( c = = - 1 )
break ;
switch ( c )
{
default :
Con_Printf ( " SV_ReadClientMessage: unknown command char \n " ) ;
SV_DropClient ( cl ) ;
return ;
case clc_nop :
break ;
case clc_delta :
cl - > delta_sequence = MSG_ReadByte ( ) ;
break ;
case clc_move :
if ( move_issued )
return ; // someone is trying to cheat...
move_issued = true ;
checksumIndex = MSG_GetReadCount ( ) ;
checksum = ( byte ) MSG_ReadByte ( ) ;
// read loss percentage
cl - > lossage = MSG_ReadByte ( ) ;
MSG_ReadDeltaUsercmd ( & nullcmd , & oldest ) ;
MSG_ReadDeltaUsercmd ( & oldest , & oldcmd ) ;
MSG_ReadDeltaUsercmd ( & oldcmd , & newcmd ) ;
if ( cl - > state ! = cs_spawned )
break ;
// if the checksum fails, ignore the rest of the packet
calculatedChecksum = COM_BlockSequenceCRCByte (
net_message . data + checksumIndex + 1 ,
MSG_GetReadCount ( ) - checksumIndex - 1 ,
seq_hash ) ;
if ( calculatedChecksum ! = checksum )
{
Con_DPrintf ( " Failed command checksum for %s(%d) (%d != %d) \n " ,
cl - > name , cl - > netchan . incoming_sequence , checksum , calculatedChecksum ) ;
return ;
}
if ( ! sv . paused ) {
SV_PreRunCmd ( ) ;
2000-01-15 22:52:56 +00:00
loss = net_drop ;
if ( net_drop < 20 ) {
while ( net_drop > 2 ) {
2000-01-19 16:35:26 +00:00
SV_RunCmd ( & cl - > lastcmd , 0 ) ;
1999-12-25 05:22:39 +00:00
net_drop - - ;
}
if ( net_drop > 1 )
2000-01-19 16:35:26 +00:00
SV_RunCmd ( & oldest , 0 ) ;
1999-12-25 05:22:39 +00:00
if ( net_drop > 0 )
2000-01-19 16:35:26 +00:00
SV_RunCmd ( & oldcmd , 0 ) ;
1999-12-25 05:22:39 +00:00
}
2000-01-15 22:52:56 +00:00
2000-01-07 05:04:18 +00:00
SV_RunCmd ( & newcmd , 0 ) ;
1999-12-25 05:22:39 +00:00
SV_PostRunCmd ( ) ;
}
cl - > lastcmd = newcmd ;
cl - > lastcmd . buttons = 0 ; // avoid multiple fires on lag
break ;
case clc_stringcmd :
s = MSG_ReadString ( ) ;
SV_ExecuteUserCommand ( s ) ;
break ;
case clc_tmove :
o [ 0 ] = MSG_ReadCoord ( ) ;
o [ 1 ] = MSG_ReadCoord ( ) ;
o [ 2 ] = MSG_ReadCoord ( ) ;
// only allowed by spectators
if ( host_client - > spectator ) {
VectorCopy ( o , sv_player - > v . origin ) ;
SV_LinkEdict ( sv_player , false ) ;
}
break ;
case clc_upload :
SV_NextUpload ( ) ;
break ;
}
}
}
/*
= = = = = = = = = = = = = =
SV_UserInit
= = = = = = = = = = = = = =
*/
void SV_UserInit ( void )
{
Cvar_RegisterVariable ( & cl_rollspeed ) ;
Cvar_RegisterVariable ( & cl_rollangle ) ;
Cvar_RegisterVariable ( & sv_spectalk ) ;
Cvar_RegisterVariable ( & sv_mapcheck ) ;
}