2011-05-09 22:00:00 +02:00
/*
sv_main . c - server main loop
Copyright ( C ) 2007 Uncle Mike
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 3 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 .
*/
2007-06-21 22:00:00 +02:00
2008-06-09 22:00:00 +02:00
# include "common.h"
2007-06-21 22:00:00 +02:00
# include "server.h"
2010-08-06 22:00:00 +02:00
# include "net_encode.h"
2007-06-21 22:00:00 +02:00
2011-04-05 22:00:00 +02:00
# define HEARTBEAT_SECONDS 300.0f // 300 seconds
2009-09-17 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
// server cvars
CVAR_DEFINE_AUTO ( sv_lan , " 0 " , 0 , " server is a lan server ( no heartbeat, no authentication, no non-class C addresses, 9999.0 rate, etc. " ) ;
CVAR_DEFINE_AUTO ( sv_lan_rate , " 20000.0 " , 0 , " rate for lan server " ) ;
CVAR_DEFINE_AUTO ( sv_aim , " 1 " , FCVAR_ARCHIVE | FCVAR_SERVER , " auto aiming option " ) ;
CVAR_DEFINE_AUTO ( sv_unlag , " 1 " , 0 , " allow lag compensation on server-side " ) ;
CVAR_DEFINE_AUTO ( sv_maxunlag , " 0.5 " , 0 , " max latency value which can be interpolated (by default ping should not exceed 500 units) " ) ;
CVAR_DEFINE_AUTO ( sv_unlagpush , " 0.0 " , 0 , " interpolation bias for unlag time " ) ;
CVAR_DEFINE_AUTO ( sv_unlagsamples , " 1 " , 0 , " max samples to interpolate " ) ;
CVAR_DEFINE_AUTO ( rcon_password , " " , 0 , " remote connect password " ) ;
CVAR_DEFINE_AUTO ( sv_filterban , " 1 " , 0 , " filter banned users " ) ;
CVAR_DEFINE_AUTO ( sv_cheats , " 0 " , FCVAR_SERVER , " allow cheats on server " ) ;
CVAR_DEFINE_AUTO ( sv_instancedbaseline , " 1 " , 0 , " allow to use instanced baselines to saves network overhead " ) ;
CVAR_DEFINE_AUTO ( sv_contact , " 1 " , FCVAR_ARCHIVE | FCVAR_SERVER , " server techincal support contact address or web-page " ) ;
CVAR_DEFINE_AUTO ( sv_minupdaterate , " 10.0 " , FCVAR_ARCHIVE , " minimal value for 'cl_updaterate' window " ) ;
CVAR_DEFINE_AUTO ( sv_maxupdaterate , " 30.0 " , FCVAR_ARCHIVE , " maximal value for 'cl_updaterate' window " ) ;
CVAR_DEFINE_AUTO ( sv_minrate , " 0 " , FCVAR_SERVER , " min bandwidth rate allowed on server, 0 == unlimited " ) ;
CVAR_DEFINE_AUTO ( sv_maxrate , " 0 " , FCVAR_SERVER , " max bandwidth rate allowed on server, 0 == unlimited " ) ;
CVAR_DEFINE_AUTO ( sv_logrelay , " 0 " , FCVAR_ARCHIVE , " allow log messages from remote machines to be logged on this server " ) ;
CVAR_DEFINE_AUTO ( sv_newunit , " 0 " , 0 , " clear level-saves from previous SP game chapter to help keep .sav file size as minimum " ) ;
CVAR_DEFINE_AUTO ( sv_clienttrace , " 1 " , FCVAR_SERVER , " 0 = big box(Quake), 0.5 = halfsize, 1 = normal (100%), otherwise it's a scaling factor " ) ;
CVAR_DEFINE_AUTO ( sv_timeout , " 65 " , 0 , " after this many seconds without a message from a client, the client is dropped " ) ;
CVAR_DEFINE_AUTO ( sv_failuretime , " 0.5 " , 0 , " after this long without a packet from client, don't send any more until client starts sending again " ) ;
CVAR_DEFINE_AUTO ( sv_password , " " , FCVAR_SERVER | FCVAR_PROTECTED , " server password for entry into multiplayer games " ) ;
CVAR_DEFINE_AUTO ( sv_proxies , " 1 " , FCVAR_SERVER , " maximum count of allowed proxies for HLTV spectating " ) ;
CVAR_DEFINE_AUTO ( sv_send_logos , " 1 " , 0 , " send custom decal logo to other players so they can view his too " ) ;
CVAR_DEFINE_AUTO ( sv_send_resources , " 1 " , 0 , " allow to download missed resources for players " ) ;
CVAR_DEFINE_AUTO ( sv_logbans , " 0 " , 0 , " print into the server log info about player bans " ) ;
CVAR_DEFINE_AUTO ( sv_allow_upload , " 1 " , FCVAR_SERVER , " allow uploading custom resources on a server " ) ;
CVAR_DEFINE_AUTO ( sv_allow_download , " 1 " , FCVAR_SERVER , " allow downloading custom resources to the client " ) ;
CVAR_DEFINE_AUTO ( sv_downloadurl , " " , FCVAR_PROTECTED , " location from which clients can download missing files " ) ;
CVAR_DEFINE ( sv_consistency , " mp_consistency " , " 1 " , FCVAR_SERVER , " enbale consistency check in multiplayer " ) ;
// game-related cvars
CVAR_DEFINE_AUTO ( mapcyclefile , " mapcycle.txt " , 0 , " name of multiplayer map cycle configuration file " ) ;
CVAR_DEFINE_AUTO ( motdfile , " motd.txt " , 0 , " name of 'message of the day' file " ) ;
CVAR_DEFINE_AUTO ( logsdir , " logs " , 0 , " place to store multiplayer logs " ) ;
CVAR_DEFINE_AUTO ( bannedcfgfile , " banned.cfg " , 0 , " name of list of banned users " ) ;
CVAR_DEFINE_AUTO ( deathmatch , " 0 " , 0 , " deathmatch mode in multiplayer game " ) ;
CVAR_DEFINE_AUTO ( coop , " 0 " , 0 , " cooperative mode in multiplayer game " ) ;
CVAR_DEFINE_AUTO ( skill , " 1 " , 0 , " skill level in singleplayer game " ) ;
// physic-related variables
CVAR_DEFINE_AUTO ( sv_gravity , " 800 " , FCVAR_MOVEVARS , " world gravity value " ) ;
CVAR_DEFINE_AUTO ( sv_stopspeed , " 100 " , FCVAR_MOVEVARS , " how fast you come to a complete stop " ) ;
CVAR_DEFINE_AUTO ( sv_maxspeed , " 320 " , FCVAR_MOVEVARS , " maximum speed a player can accelerate to when on ground " ) ;
CVAR_DEFINE_AUTO ( sv_spectatormaxspeed , " 500 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " maximum speed a spectator can accelerate in air " ) ;
CVAR_DEFINE_AUTO ( sv_accelerate , " 10 " , FCVAR_MOVEVARS , " rate at which a player accelerates to sv_maxspeed " ) ;
CVAR_DEFINE_AUTO ( sv_airaccelerate , " 10 " , FCVAR_MOVEVARS , " rate at which a player accelerates to sv_maxspeed while in the air " ) ;
CVAR_DEFINE_AUTO ( sv_wateraccelerate , " 10 " , FCVAR_MOVEVARS , " rate at which a player accelerates to sv_maxspeed while in the water " ) ;
CVAR_DEFINE_AUTO ( sv_friction , " 4 " , FCVAR_MOVEVARS , " how fast you slow down " ) ;
CVAR_DEFINE ( sv_edgefriction , " edgefriction " , " 2 " , FCVAR_MOVEVARS , " how much you slow down when nearing a ledge you might fall off " ) ;
CVAR_DEFINE_AUTO ( sv_waterfriction , " 1 " , FCVAR_MOVEVARS , " how fast you slow down in water " ) ;
CVAR_DEFINE_AUTO ( sv_bounce , " 1 " , FCVAR_MOVEVARS , " bounce factor for entities with MOVETYPE_BOUNCE " ) ;
CVAR_DEFINE_AUTO ( sv_stepsize , " 18 " , FCVAR_MOVEVARS , " how high you and NPS's can step up " ) ;
CVAR_DEFINE_AUTO ( sv_maxvelocity , " 2000 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " max velocity for all things in the world " ) ;
CVAR_DEFINE_AUTO ( sv_zmax , " 4096 " , FCVAR_MOVEVARS | FCVAR_SPONLY , " maximum viewable distance " ) ;
CVAR_DEFINE_AUTO ( sv_wateramp , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " world waveheight factor " ) ;
CVAR_DEFINE ( sv_footsteps , " mp_footsteps " , " 1 " , FCVAR_MOVEVARS , " world gravity value " ) ;
CVAR_DEFINE_AUTO ( sv_skyname , " desert " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " skybox name (can be dynamically changed in-game) " ) ;
CVAR_DEFINE_AUTO ( sv_rollangle , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED | FCVAR_ARCHIVE , " how much to tilt the view when strafing " ) ;
CVAR_DEFINE_AUTO ( sv_rollspeed , " 200 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " how much strafing is necessary to tilt the view " ) ;
CVAR_DEFINE_AUTO ( sv_skycolor_r , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " skylight red component value " ) ;
CVAR_DEFINE_AUTO ( sv_skycolor_g , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " skylight green component value " ) ;
CVAR_DEFINE_AUTO ( sv_skycolor_b , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " skylight blue component value " ) ;
CVAR_DEFINE_AUTO ( sv_skyvec_x , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " skylight direction by x-axis " ) ;
CVAR_DEFINE_AUTO ( sv_skyvec_y , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " skylight direction by y-axis " ) ;
CVAR_DEFINE_AUTO ( sv_skyvec_z , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " skylight direction by z-axis " ) ;
CVAR_DEFINE_AUTO ( sv_wateralpha , " 1 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " world surfaces water transparency factor. 1.0 - solid, 0.0 - fully transparent " ) ;
CVAR_DEFINE_AUTO ( sv_skydir_x , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " sky rotation factor around x-axis " ) ;
CVAR_DEFINE_AUTO ( sv_skydir_y , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " sky rotation factor around y-axis " ) ;
CVAR_DEFINE_AUTO ( sv_skydir_z , " 1 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " sky rotation factor around z-axis " ) ; // g-cont. add default sky rotate direction
CVAR_DEFINE_AUTO ( sv_skyangle , " 0 " , FCVAR_MOVEVARS | FCVAR_UNLOGGED , " skybox rotational angle (in degrees) " ) ;
CVAR_DEFINE_AUTO ( sv_skyspeed , " 0 " , 0 , " skybox rotational speed " ) ;
// obsolete cvars which we should keep because game DLL's will be relies on it
CVAR_DEFINE_AUTO ( showtriggers , " 0 " , FCVAR_LATCH , " debug cvar shows triggers " ) ;
CVAR_DEFINE_AUTO ( sv_airmove , " 1 " , FCVAR_SERVER , " obsolete, compatibility issues " ) ;
// gore-related cvars
CVAR_DEFINE_AUTO ( violence_hblood , " 1 " , 0 , " draw human blood " ) ;
CVAR_DEFINE_AUTO ( violence_ablood , " 1 " , 0 , " draw alien blood " ) ;
CVAR_DEFINE_AUTO ( violence_hgibs , " 1 " , 0 , " show human gib entities " ) ;
CVAR_DEFINE_AUTO ( violence_agibs , " 1 " , 0 , " show alien gib entities " ) ;
2010-12-09 22:00:00 +01:00
convar_t * sv_novis ; // disable server culling entities by vis
2010-10-22 22:00:00 +02:00
convar_t * sv_pausable ;
convar_t * timeout ; // seconds without any message
convar_t * zombietime ; // seconds to sink messages after disconnect
convar_t * hostname ;
convar_t * sv_lighting_modulate ;
convar_t * sv_maxclients ;
convar_t * sv_check_errors ;
2011-04-05 22:00:00 +02:00
convar_t * public_server ; // should heartbeats be sent
convar_t * sv_reconnect_limit ; // minimum seconds between connect messages
2011-02-05 22:00:00 +01:00
convar_t * sv_allow_studio_attachment_angles ;
2011-04-05 22:00:00 +02:00
convar_t * sv_allow_rotate_pushables ;
2012-05-23 22:00:00 +02:00
convar_t * sv_validate_changelevel ;
2010-12-27 22:00:00 +01:00
convar_t * sv_sendvelocity ;
2010-06-16 22:00:00 +02:00
void Master_Shutdown ( void ) ;
2007-06-21 22:00:00 +02:00
//============================================================================
2010-08-06 22:00:00 +02:00
/*
= = = = = = = = = = = = = = = =
SV_HasActivePlayers
returns true if server have spawned players
= = = = = = = = = = = = = = = =
*/
2010-10-26 22:00:00 +02:00
qboolean SV_HasActivePlayers ( void )
2010-08-06 22:00:00 +02:00
{
int i ;
// server inactive
if ( ! svs . clients ) return false ;
2017-02-12 22:00:00 +01:00
for ( i = 0 ; i < svs . maxclients ; i + + )
2010-08-06 22:00:00 +02:00
{
if ( svs . clients [ i ] . state = = cs_spawned )
return true ;
}
return false ;
}
2009-11-10 22:00:00 +01:00
/*
= = = = = = = = = = = = = = = = = = =
SV_UpdateMovevars
check movevars for changes every frame
send updates to client if changed
= = = = = = = = = = = = = = = = = = =
*/
2012-04-25 22:00:00 +02:00
void SV_UpdateMovevars ( qboolean initialize )
2009-11-10 22:00:00 +01:00
{
2017-02-12 22:00:00 +01:00
if ( ! initialize & & ! host . movevars_changed )
2012-04-25 22:00:00 +02:00
return ;
2010-02-07 22:00:00 +01:00
2010-12-14 22:00:00 +01:00
// check range
2017-02-12 22:00:00 +01:00
if ( sv_zmax . value < 256.0f ) Cvar_SetValue ( " sv_zmax " , 256.0f ) ;
2016-09-14 23:00:00 +02:00
// clamp it right
if ( host . features & ENGINE_WRITE_LARGE_COORD )
{
2017-02-12 22:00:00 +01:00
if ( sv_zmax . value > 131070.0f )
Cvar_SetValue ( " sv_zmax " , 131070.0f ) ;
2016-09-14 23:00:00 +02:00
}
else
{
2017-02-12 22:00:00 +01:00
if ( sv_zmax . value > 32767.0f )
Cvar_SetValue ( " sv_zmax " , 32767.0f ) ;
2016-09-14 23:00:00 +02:00
}
2010-12-14 22:00:00 +01:00
2017-02-12 22:00:00 +01:00
svgame . movevars . gravity = sv_gravity . value ;
svgame . movevars . stopspeed = sv_stopspeed . value ;
svgame . movevars . maxspeed = sv_maxspeed . value ;
svgame . movevars . spectatormaxspeed = sv_spectatormaxspeed . value ;
svgame . movevars . accelerate = sv_accelerate . value ;
svgame . movevars . airaccelerate = sv_airaccelerate . value ;
svgame . movevars . wateraccelerate = sv_wateraccelerate . value ;
svgame . movevars . friction = sv_friction . value ;
svgame . movevars . edgefriction = sv_edgefriction . value ;
svgame . movevars . waterfriction = sv_waterfriction . value ;
svgame . movevars . bounce = sv_bounce . value ;
svgame . movevars . stepsize = sv_stepsize . value ;
svgame . movevars . maxvelocity = sv_maxvelocity . value ;
svgame . movevars . zmax = sv_zmax . value ;
svgame . movevars . waveHeight = sv_wateramp . value ;
Q_strncpy ( svgame . movevars . skyName , sv_skyname . string , sizeof ( svgame . movevars . skyName ) ) ;
svgame . movevars . footsteps = sv_footsteps . value ;
svgame . movevars . rollangle = sv_rollangle . value ;
svgame . movevars . rollspeed = sv_rollspeed . value ;
svgame . movevars . skycolor_r = sv_skycolor_r . value ;
svgame . movevars . skycolor_g = sv_skycolor_g . value ;
svgame . movevars . skycolor_b = sv_skycolor_b . value ;
svgame . movevars . skyvec_x = sv_skyvec_x . value ;
svgame . movevars . skyvec_y = sv_skyvec_y . value ;
svgame . movevars . skyvec_z = sv_skyvec_z . value ;
svgame . movevars . skydir_x = sv_skydir_x . value ;
svgame . movevars . skydir_y = sv_skydir_y . value ;
svgame . movevars . skydir_z = sv_skydir_z . value ;
svgame . movevars . skyangle = sv_skyangle . value ;
svgame . movevars . wateralpha = sv_wateralpha . value ;
2012-06-26 22:00:00 +02:00
svgame . movevars . features = host . features ; // just in case. not really need
2017-02-12 22:00:00 +01:00
svgame . movevars . entgravity = 1.0f ;
2009-11-10 22:00:00 +01:00
2012-12-18 21:00:00 +01:00
if ( initialize ) return ; // too early
2012-04-25 22:00:00 +02:00
2010-10-09 22:00:00 +02:00
if ( MSG_WriteDeltaMovevars ( & sv . reliable_datagram , & svgame . oldmovevars , & svgame . movevars ) )
2016-11-17 22:00:00 +01:00
memcpy ( & svgame . oldmovevars , & svgame . movevars , sizeof ( movevars_t ) ) ; // oldstate changed
2010-10-09 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
host . movevars_changed = false ;
2010-03-30 22:00:00 +02:00
}
2010-10-14 22:00:00 +02:00
/*
= = = = = = = = = = = = = = = = =
SV_CheckCmdTimes
= = = = = = = = = = = = = = = = =
*/
void SV_CheckCmdTimes ( void )
{
sv_client_t * cl ;
static double lastreset = 0 ;
2017-02-05 22:00:00 +01:00
float diff ;
2010-10-14 22:00:00 +02:00
int i ;
2017-02-05 22:00:00 +01:00
if ( Host_IsLocalGame ( ) )
return ;
2011-04-05 22:00:00 +02:00
if ( ( host . realtime - lastreset ) < 1.0 )
2010-10-14 22:00:00 +02:00
return ;
lastreset = host . realtime ;
2017-02-12 22:00:00 +01:00
for ( i = 0 , cl = svs . clients ; i < svs . maxclients ; i + + , cl + + )
2010-10-14 22:00:00 +02:00
{
if ( cl - > state ! = cs_spawned )
continue ;
2017-02-05 22:00:00 +01:00
if ( cl - > connecttime = = 0.0 )
2010-10-14 22:00:00 +02:00
{
2017-02-05 22:00:00 +01:00
cl - > connecttime = host . realtime ;
2010-10-14 22:00:00 +02:00
}
2017-02-05 22:00:00 +01:00
diff = cl - > connecttime + cl - > cmdtime - host . realtime ;
2010-10-14 22:00:00 +02:00
2017-02-05 22:00:00 +01:00
if ( diff > net_clockwindow - > value )
2010-10-14 22:00:00 +02:00
{
2017-02-05 22:00:00 +01:00
cl - > ignorecmdtime = net_clockwindow - > value + host . realtime ;
cl - > cmdtime = host . realtime - cl - > connecttime ;
2010-10-14 22:00:00 +02:00
}
2017-02-05 22:00:00 +01:00
else if ( diff < - net_clockwindow - > value )
2010-10-14 22:00:00 +02:00
{
2017-02-05 22:00:00 +01:00
cl - > cmdtime = host . realtime - cl - > connecttime ;
2010-10-14 22:00:00 +02:00
}
}
}
2009-06-24 22:00:00 +02:00
/*
= = = = = = = = = = = = = = = = =
SV_ReadPackets
= = = = = = = = = = = = = = = = =
*/
void SV_ReadPackets ( void )
{
sv_client_t * cl ;
2016-08-13 23:00:00 +02:00
int i , qport ;
size_t curSize ;
2007-06-21 22:00:00 +02:00
2010-08-04 22:00:00 +02:00
while ( NET_GetPacket ( NS_SERVER , & net_from , net_message_buffer , & curSize ) )
2007-06-21 22:00:00 +02:00
{
2016-11-14 22:00:00 +01:00
MSG_Init ( & net_message , " ClientPacket " , net_message_buffer , curSize ) ;
2010-08-04 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
// check for connectionless packet (0xffffffff) first
2016-11-14 22:00:00 +01:00
if ( MSG_GetMaxBytes ( & net_message ) > = 4 & & * ( int * ) net_message . pData = = - 1 )
2007-06-21 22:00:00 +02:00
{
2016-08-12 23:00:00 +02:00
if ( ! svs . initialized )
{
char * args , * c ;
2016-11-14 22:00:00 +01:00
MSG_Clear ( & net_message ) ;
MSG_ReadLong ( & net_message ) ; // skip the -1 marker
2016-08-12 23:00:00 +02:00
2016-11-14 22:00:00 +01:00
args = MSG_ReadStringLine ( & net_message ) ;
2016-08-12 23:00:00 +02:00
Cmd_TokenizeString ( args ) ;
c = Cmd_Argv ( 0 ) ;
if ( ! Q_strcmp ( c , " rcon " ) )
SV_RemoteCommand ( net_from , & net_message ) ;
}
else SV_ConnectionlessPacket ( net_from , & net_message ) ;
2009-06-24 22:00:00 +02:00
continue ;
2007-06-21 22:00:00 +02:00
}
2009-06-24 22:00:00 +02:00
// read the qport out of the message so we can fix up
// stupid address translating routers
2016-11-14 22:00:00 +01:00
MSG_Clear ( & net_message ) ;
MSG_ReadLong ( & net_message ) ; // sequence number
MSG_ReadLong ( & net_message ) ; // sequence number
qport = ( int ) MSG_ReadShort ( & net_message ) & 0xffff ;
2009-06-24 22:00:00 +02:00
// check for packets from connected clients
2017-02-12 22:00:00 +01:00
for ( i = 0 , cl = svs . clients ; i < svs . maxclients ; i + + , cl + + )
2009-06-24 22:00:00 +02:00
{
2016-11-21 22:00:00 +01:00
if ( cl - > state = = cs_free | | FBitSet ( cl - > flags , FCL_FAKECLIENT ) )
2011-04-05 22:00:00 +02:00
continue ;
if ( ! NET_CompareBaseAdr ( net_from , cl - > netchan . remote_address ) )
continue ;
if ( cl - > netchan . qport ! = qport )
continue ;
2009-06-24 22:00:00 +02:00
if ( cl - > netchan . remote_address . port ! = net_from . port )
2007-06-21 22:00:00 +02:00
{
2016-11-21 22:00:00 +01:00
MsgDev ( D_NOTE , " SV_ReadPackets: fixing up a translated port \n " ) ;
2009-06-24 22:00:00 +02:00
cl - > netchan . remote_address . port = net_from . port ;
2007-06-21 22:00:00 +02:00
}
2010-04-03 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
if ( Netchan_Process ( & cl - > netchan , & net_message ) )
{
2017-02-21 22:00:00 +01:00
if ( ( svs . maxclients = = 1 & & ! host_limitlocal - > value ) | | ( cl - > state ! = cs_spawned ) )
2016-11-21 22:00:00 +01:00
SetBits ( cl - > flags , FCL_SEND_NET_MESSAGE ) ; // reply at end of frame
2010-04-03 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
// this is a valid, sequenced packet, so process it
if ( cl - > state ! = cs_zombie )
{
2010-10-09 22:00:00 +02:00
cl - > lastmessage = host . realtime ; // don't timeout
2009-06-24 22:00:00 +02:00
SV_ExecuteClientMessage ( cl , & net_message ) ;
2016-11-21 22:00:00 +01:00
svgame . globals - > frametime = sv . frametime ;
2012-04-01 22:00:00 +02:00
svgame . globals - > time = sv . time ;
2009-06-24 22:00:00 +02:00
}
}
2010-10-07 22:00:00 +02:00
2011-04-05 22:00:00 +02:00
// fragmentation/reassembly sending takes priority over all game messages, want this in the future?
2010-10-07 22:00:00 +02:00
if ( Netchan_IncomingReady ( & cl - > netchan ) )
{
2017-02-05 22:00:00 +01:00
if ( Netchan_CopyNormalFragments ( & cl - > netchan , & net_message , & curSize ) )
2010-10-07 22:00:00 +02:00
{
2017-02-05 22:00:00 +01:00
MSG_Init ( & net_message , " ClientPacket " , net_message_buffer , curSize ) ;
2017-02-07 22:00:00 +01:00
2017-02-12 22:00:00 +01:00
if ( svs . maxclients = = 1 | | cl - > state ! = cs_spawned )
2017-02-07 22:00:00 +01:00
SetBits ( cl - > flags , FCL_SEND_NET_MESSAGE ) ; // reply at end of frame
// this is a valid, sequenced packet, so process it
if ( cl - > state ! = cs_zombie )
{
cl - > lastmessage = host . realtime ; // don't timeout
SV_ExecuteClientMessage ( cl , & net_message ) ;
svgame . globals - > frametime = sv . frametime ;
svgame . globals - > time = sv . time ;
}
2010-10-07 22:00:00 +02:00
}
if ( Netchan_CopyFileFragments ( & cl - > netchan , & net_message ) )
{
2011-07-07 22:00:00 +02:00
SV_ProcessFile ( cl , cl - > netchan . incomingfilename ) ;
2010-10-07 22:00:00 +02:00
}
}
2009-06-24 22:00:00 +02:00
break ;
2007-06-21 22:00:00 +02:00
}
2010-06-20 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
if ( i ! = svs . maxclients )
2010-06-20 22:00:00 +02:00
continue ;
2009-06-22 22:00:00 +02:00
}
2016-12-09 22:00:00 +01:00
svs . currentPlayer = NULL ;
svs . currentPlayerNum = - 1 ;
2009-06-22 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
/*
= = = = = = = = = = = = = = = = = =
SV_CheckTimeouts
If a packet has not been received from a client for timeout - > value
seconds , drop the conneciton . Server frames are used instead of
realtime to avoid dropping the local client while debugging .
2008-07-09 22:00:00 +02:00
When a client is normally dropped , the sv_client_t goes into a zombie state
2007-06-21 22:00:00 +02:00
for a few seconds to make sure any final reliable message gets resent
if necessary
= = = = = = = = = = = = = = = = = =
*/
2008-07-12 22:00:00 +02:00
void SV_CheckTimeouts ( void )
2007-06-21 22:00:00 +02:00
{
2008-07-09 22:00:00 +02:00
sv_client_t * cl ;
2010-10-09 22:00:00 +02:00
float droppoint ;
float zombiepoint ;
2009-11-10 22:00:00 +01:00
int i , numclients = 0 ;
2007-06-21 22:00:00 +02:00
2010-10-09 22:00:00 +02:00
droppoint = host . realtime - timeout - > value ;
zombiepoint = host . realtime - zombietime - > value ;
2008-07-31 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
for ( i = 0 , cl = svs . clients ; i < svs . maxclients ; i + + , cl + + )
2007-06-21 22:00:00 +02:00
{
2009-11-10 22:00:00 +01:00
if ( cl - > state > = cs_connected )
{
2016-11-21 22:00:00 +01:00
if ( cl - > edict & & ! FBitSet ( cl - > edict - > v . flags , FL_SPECTATOR | FL_FAKECLIENT ) )
2009-11-10 22:00:00 +01:00
numclients + + ;
}
2009-06-24 22:00:00 +02:00
// fake clients do not timeout
2016-11-21 22:00:00 +01:00
if ( FBitSet ( cl - > flags , FCL_FAKECLIENT ) )
cl - > lastmessage = host . realtime ;
2010-06-20 22:00:00 +02:00
2007-06-21 22:00:00 +02:00
// message times may be wrong across a changelevel
2010-10-09 22:00:00 +02:00
if ( cl - > lastmessage > host . realtime )
cl - > lastmessage = host . realtime ;
2010-06-20 22:00:00 +02:00
2008-07-12 22:00:00 +02:00
if ( cl - > state = = cs_zombie & & cl - > lastmessage < zombiepoint )
2007-06-21 22:00:00 +02:00
{
2008-07-12 22:00:00 +02:00
cl - > state = cs_free ; // can now be reused
2007-06-21 22:00:00 +02:00
continue ;
}
2012-12-18 21:00:00 +01:00
2016-11-21 22:00:00 +01:00
if ( ( cl - > state = = cs_connected | | cl - > state = = cs_spawned ) & & cl - > lastmessage < droppoint )
2007-06-21 22:00:00 +02:00
{
2016-11-21 22:00:00 +01:00
if ( ! NET_IsLocalAddress ( cl - > netchan . remote_address ) )
{
SV_BroadcastPrintf ( NULL , PRINT_HIGH , " %s timed out \n " , cl - > name ) ;
SV_DropClient ( cl ) ;
cl - > state = cs_free ; // don't bother with zombie state
}
2007-06-21 22:00:00 +02:00
}
}
2009-11-10 22:00:00 +01:00
if ( sv . paused & & ! numclients )
{
// nobody left, unpause the server
2011-04-05 22:00:00 +02:00
SV_TogglePause ( " Pause released since no players are left. " ) ;
2009-11-10 22:00:00 +01:00
}
2007-06-21 22:00:00 +02:00
}
2009-01-14 22:00:00 +01:00
/*
= = = = = = = = = = = = = = = =
SV_PrepWorldFrame
This has to be done before the world logic , because
player processing happens outside RunWorldFrame
= = = = = = = = = = = = = = = =
*/
void SV_PrepWorldFrame ( void )
{
edict_t * ent ;
int i ;
2010-08-15 22:00:00 +02:00
for ( i = 1 ; i < svgame . numEntities ; i + + )
2009-01-14 22:00:00 +01:00
{
ent = EDICT_NUM ( i ) ;
if ( ent - > free ) continue ;
2010-04-03 22:00:00 +02:00
2016-11-21 22:00:00 +01:00
ClearBits ( ent - > v . effects , EF_MUZZLEFLASH | EF_NOINTERP ) ;
2009-01-14 22:00:00 +01:00
}
}
2011-01-09 22:00:00 +01:00
2011-07-07 22:00:00 +02:00
/*
= = = = = = = = = = = = = = = = =
SV_ProcessFile
= = = = = = = = = = = = = = = = =
*/
void SV_ProcessFile ( sv_client_t * cl , char * filename )
{
// some other file...
MsgDev ( D_INFO , " Received file %s from %s \n " , filename , cl - > name ) ;
}
2011-01-09 22:00:00 +01:00
/*
= = = = = = = = = = = = = = = = =
SV_IsSimulating
= = = = = = = = = = = = = = = = =
*/
qboolean SV_IsSimulating ( void )
{
2012-12-18 21:00:00 +01:00
if ( sv . background & & SV_Active ( ) & & CL_Active ( ) )
2011-02-22 22:00:00 +01:00
{
if ( CL_IsInConsole ( ) )
return false ;
return true ; // force simulating for background map
}
2011-04-05 22:00:00 +02:00
2016-11-21 22:00:00 +01:00
if ( FBitSet ( sv . hostflags , SVF_PLAYERSONLY ) )
2011-01-09 22:00:00 +01:00
return false ;
2016-11-21 22:00:00 +01:00
2011-01-09 22:00:00 +01:00
if ( ! SV_HasActivePlayers ( ) )
return false ;
2016-11-21 22:00:00 +01:00
2011-01-09 22:00:00 +01:00
if ( ! sv . paused & & CL_IsInGame ( ) )
return true ;
2016-11-21 22:00:00 +01:00
2011-01-09 22:00:00 +01:00
return false ;
}
2007-09-06 22:00:00 +02:00
/*
= = = = = = = = = = = = = = = = =
SV_RunGameFrame
= = = = = = = = = = = = = = = = =
*/
2016-11-21 22:00:00 +01:00
/*
= = = = = = = = = = = = = = = = =
SV_RunGameFrame
= = = = = = = = = = = = = = = = =
*/
2017-02-26 22:00:00 +01:00
void SV_RunGameFrame ( void )
2007-09-06 22:00:00 +02:00
{
2017-02-26 22:00:00 +01:00
int numFrames = 0 ; // debug
2011-01-09 22:00:00 +01:00
2017-02-26 22:00:00 +01:00
if ( ! ( sv . simulating = SV_IsSimulating ( ) ) )
return ;
2011-01-09 22:00:00 +01:00
2016-11-21 22:00:00 +01:00
if ( FBitSet ( host . features , ENGINE_FIXED_FRAMERATE ) )
{
2017-02-26 22:00:00 +01:00
sv . time_residual + = host . frametime ;
2016-11-21 22:00:00 +01:00
while ( sv . time_residual > = sv . frametime )
{
SV_Physics ( ) ;
sv . time_residual - = sv . frametime ;
sv . time + = sv . frametime ;
numFrames + + ;
}
}
else
{
SV_Physics ( ) ;
sv . time + = sv . frametime ;
2017-02-13 22:00:00 +01:00
numFrames + + ;
2016-11-21 22:00:00 +01:00
}
2007-06-21 22:00:00 +02:00
}
/*
= = = = = = = = = = = = = = = = = =
2010-10-09 22:00:00 +02:00
Host_ServerFrame
2007-06-21 22:00:00 +02:00
= = = = = = = = = = = = = = = = = =
*/
2010-10-09 22:00:00 +02:00
void Host_ServerFrame ( void )
2007-06-21 22:00:00 +02:00
{
// if server is not active, do nothing
2016-08-19 23:00:00 +02:00
if ( ! svs . initialized ) return ;
2009-02-03 22:00:00 +01:00
2016-11-21 22:00:00 +01:00
if ( FBitSet ( host . features , ENGINE_FIXED_FRAMERATE ) )
2017-02-26 22:00:00 +01:00
sv . frametime = ( 1.0 / ( double ) GAME_FPS ) ;
2017-02-13 22:00:00 +01:00
else sv . frametime = host . frametime ; // GoldSrc style
2016-11-21 22:00:00 +01:00
svgame . globals - > frametime = sv . frametime ;
2011-01-09 22:00:00 +01:00
2010-10-14 22:00:00 +02:00
// check clients timewindow
SV_CheckCmdTimes ( ) ;
2009-06-22 22:00:00 +02:00
// read packets from clients
SV_ReadPackets ( ) ;
2009-11-10 22:00:00 +01:00
// refresh physic movevars on the client side
2012-04-25 22:00:00 +02:00
SV_UpdateMovevars ( false ) ;
2009-11-10 22:00:00 +01:00
2017-02-05 22:00:00 +01:00
// check timeouts
SV_CheckTimeouts ( ) ;
2010-07-26 22:00:00 +02:00
// let everything in the world think and move
2017-02-26 22:00:00 +01:00
SV_RunGameFrame ( ) ;
2011-01-09 22:00:00 +01:00
2007-06-21 22:00:00 +02:00
// send messages back to the clients that had packets read this frame
SV_SendClientMessages ( ) ;
2009-01-14 22:00:00 +01:00
// clear edict flags for next frame
SV_PrepWorldFrame ( ) ;
2010-04-12 22:00:00 +02:00
// send a heartbeat to the master if needed
Master_Heartbeat ( ) ;
2007-06-21 22:00:00 +02:00
}
//============================================================================
2011-07-07 22:00:00 +02:00
/*
= = = = = = = = = = = = = = = = =
Master_Add
= = = = = = = = = = = = = = = = =
*/
void Master_Add ( void )
{
netadr_t adr ;
NET_Config ( true ) ; // allow remote
if ( ! NET_StringToAdr ( MASTERSERVER_ADR , & adr ) )
MsgDev ( D_INFO , " Can't resolve adr: %s \n " , MASTERSERVER_ADR ) ;
2016-08-13 23:00:00 +02:00
NET_SendPacket ( NS_SERVER , 2 , " q \xFF " , adr ) ;
2011-07-07 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
/*
= = = = = = = = = = = = = = = =
Master_Heartbeat
Send a message to the master every few minutes to
let it know we are alive , and log information
= = = = = = = = = = = = = = = =
*/
2008-12-20 22:00:00 +01:00
void Master_Heartbeat ( void )
2007-06-21 22:00:00 +02:00
{
2017-02-12 22:00:00 +01:00
if ( ! public_server - > value | | svs . maxclients = = 1 )
2011-07-07 22:00:00 +02:00
return ; // only public servers send heartbeats
2007-06-21 22:00:00 +02:00
// check for time wraparound
2010-10-09 22:00:00 +02:00
if ( svs . last_heartbeat > host . realtime )
svs . last_heartbeat = host . realtime ;
2007-06-21 22:00:00 +02:00
2010-10-09 22:00:00 +02:00
if ( ( host . realtime - svs . last_heartbeat ) < HEARTBEAT_SECONDS )
2009-02-03 22:00:00 +01:00
return ; // not time to send yet
2007-06-21 22:00:00 +02:00
2010-10-09 22:00:00 +02:00
svs . last_heartbeat = host . realtime ;
2007-06-21 22:00:00 +02:00
2011-07-07 22:00:00 +02:00
Master_Add ( ) ;
2007-06-21 22:00:00 +02:00
}
/*
= = = = = = = = = = = = = = = = =
Master_Shutdown
Informs all masters that this server is going down
= = = = = = = = = = = = = = = = =
*/
2010-06-20 22:00:00 +02:00
void Master_Shutdown ( void )
2007-06-21 22:00:00 +02:00
{
2015-12-04 22:00:00 +01:00
netadr_t adr ;
NET_Config ( true ) ; // allow remote
if ( ! NET_StringToAdr ( MASTERSERVER_ADR , & adr ) )
MsgDev ( D_INFO , " Can't resolve addr: %s \n " , MASTERSERVER_ADR ) ;
NET_SendPacket ( NS_SERVER , 2 , " \x62 \x0A " , adr ) ;
2007-06-21 22:00:00 +02:00
}
2016-08-13 23:00:00 +02:00
/*
= = = = = = = = = = = = = = = = =
SV_AddToMaster
A server info answer to master server .
Master will validate challenge and this server to public list
= = = = = = = = = = = = = = = = =
*/
void SV_AddToMaster ( netadr_t from , sizebuf_t * msg )
{
uint challenge ;
char s [ MAX_INFO_STRING ] = " 0 \n " ; // skip 2 bytes of header
int clients = 0 , bots = 0 , index ;
2017-02-12 22:00:00 +01:00
int len = sizeof ( s ) ;
2016-08-13 23:00:00 +02:00
if ( svs . clients )
{
2017-02-12 22:00:00 +01:00
for ( index = 0 ; index < svs . maxclients ; index + + )
2016-08-13 23:00:00 +02:00
{
if ( svs . clients [ index ] . state > = cs_connected )
{
2016-11-21 22:00:00 +01:00
if ( FBitSet ( svs . clients [ index ] . flags , FCL_FAKECLIENT ) )
2016-08-13 23:00:00 +02:00
bots + + ;
else clients + + ;
}
}
}
2016-11-14 22:00:00 +01:00
challenge = MSG_ReadUBitLong ( msg , sizeof ( uint ) < < 3 ) ;
2016-08-13 23:00:00 +02:00
2017-02-12 22:00:00 +01:00
Info_SetValueForKey ( s , " protocol " , va ( " %d " , PROTOCOL_VERSION ) , len ) ; // protocol version
Info_SetValueForKey ( s , " challenge " , va ( " %u " , challenge ) , len ) ; // challenge number
Info_SetValueForKey ( s , " players " , va ( " %d " , clients ) , len ) ; // current player number, without bots
Info_SetValueForKey ( s , " max " , va ( " %d " , svs . maxclients ) , len ) ; // max_players
Info_SetValueForKey ( s , " bots " , va ( " %d " , bots ) , len ) ; // bot count
Info_SetValueForKey ( s , " gamedir " , GI - > gamedir , len ) ; // gamedir
Info_SetValueForKey ( s , " map " , sv . name , len ) ; // current map
Info_SetValueForKey ( s , " type " , ( host . type = = HOST_DEDICATED ) ? " d " : " l " , len ) ; // dedicated or local
Info_SetValueForKey ( s , " password " , " 0 " , len ) ; // is password set
Info_SetValueForKey ( s , " os " , " w " , len ) ; // Windows
Info_SetValueForKey ( s , " secure " , " 0 " , len ) ; // server anti-cheat
Info_SetValueForKey ( s , " lan " , " 0 " , len ) ; // LAN servers doesn't send info to master
Info_SetValueForKey ( s , " version " , va ( " %g " , XASH_VERSION ) , len ) ; // server region. 255 -- all regions
Info_SetValueForKey ( s , " region " , " 255 " , len ) ; // server region. 255 -- all regions
Info_SetValueForKey ( s , " product " , GI - > gamefolder , len ) ; // product? Where is the difference with gamedir?
2016-08-13 23:00:00 +02:00
NET_SendPacket ( NS_SERVER , Q_strlen ( s ) , s , from ) ;
}
2007-06-21 22:00:00 +02:00
//============================================================================
/*
= = = = = = = = = = = = = = =
SV_Init
2008-12-15 22:00:00 +01:00
Only called at startup , not for each game
2007-06-21 22:00:00 +02:00
= = = = = = = = = = = = = = =
*/
2008-08-04 22:00:00 +02:00
void SV_Init ( void )
2007-06-21 22:00:00 +02:00
{
2017-02-05 22:00:00 +01:00
SV_InitHostCommands ( ) ;
2007-06-21 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
Cvar_Get ( " protocol " , va ( " %i " , PROTOCOL_VERSION ) , FCVAR_READ_ONLY , " displays server protocol version " ) ;
Cvar_Get ( " defaultmap " , " " , FCVAR_SERVER , " holds the multiplayer mapname " ) ;
Cvar_Get ( " suitvolume " , " 0.25 " , FCVAR_ARCHIVE , " HEV suit volume " ) ;
Cvar_Get ( " sv_background " , " 0 " , FCVAR_READ_ONLY , " indicate what background map is running " ) ;
Cvar_Get ( " gamedir " , GI - > gamefolder , FCVAR_SERVER | FCVAR_READ_ONLY , " game folder " ) ;
2011-04-08 22:00:00 +02:00
Cvar_Get ( " sv_alltalk " , " 1 " , 0 , " allow to talking for all players (legacy, unused) " ) ;
2017-02-12 22:00:00 +01:00
Cvar_Get ( " sv_allow_PhysX " , " 1 " , FCVAR_ARCHIVE , " allow XashXT to usage PhysX engine " ) ; // XashXT cvar
Cvar_Get ( " sv_precache_meshes " , " 1 " , FCVAR_ARCHIVE , " cache SOLID_CUSTOM meshes before level loading " ) ; // Paranoia 2 cvar
2017-02-21 22:00:00 +01:00
Cvar_Get ( " mapcyclefile " , " mapcycle.txt " , 0 , " name of config file for map changing rules " ) ;
Cvar_Get ( " servercfgfile " , " server.cfg " , 0 , " name of dedicated server configuration file " ) ;
Cvar_Get ( " lservercfgfile " , " listenserver.cfg " , 0 , " name of listen server configuration file " ) ;
2017-02-12 22:00:00 +01:00
Cvar_RegisterVariable ( & sv_zmax ) ;
Cvar_RegisterVariable ( & sv_wateramp ) ;
Cvar_RegisterVariable ( & sv_skycolor_r ) ;
Cvar_RegisterVariable ( & sv_skycolor_g ) ;
Cvar_RegisterVariable ( & sv_skycolor_b ) ;
Cvar_RegisterVariable ( & sv_skyvec_x ) ;
Cvar_RegisterVariable ( & sv_skyvec_y ) ;
Cvar_RegisterVariable ( & sv_skyvec_z ) ;
Cvar_RegisterVariable ( & sv_skyname ) ;
Cvar_RegisterVariable ( & sv_skydir_x ) ;
Cvar_RegisterVariable ( & sv_skydir_y ) ;
Cvar_RegisterVariable ( & sv_skydir_z ) ;
Cvar_RegisterVariable ( & sv_skyangle ) ;
Cvar_RegisterVariable ( & sv_skyspeed ) ;
Cvar_RegisterVariable ( & sv_footsteps ) ;
Cvar_RegisterVariable ( & sv_wateralpha ) ;
Cvar_RegisterVariable ( & sv_cheats ) ;
Cvar_RegisterVariable ( & sv_airmove ) ;
Cvar_RegisterVariable ( & showtriggers ) ;
Cvar_RegisterVariable ( & sv_aim ) ;
Cvar_RegisterVariable ( & motdfile ) ;
Cvar_RegisterVariable ( & deathmatch ) ;
Cvar_RegisterVariable ( & coop ) ;
Cvar_RegisterVariable ( & skill ) ;
Cvar_RegisterVariable ( & rcon_password ) ;
Cvar_RegisterVariable ( & sv_stepsize ) ;
Cvar_RegisterVariable ( & sv_newunit ) ;
hostname = Cvar_Get ( " hostname " , " unnamed " , FCVAR_SERVER | FCVAR_ARCHIVE , " host name " ) ;
timeout = Cvar_Get ( " timeout " , " 125 " , FCVAR_SERVER , " connection timeout " ) ;
zombietime = Cvar_Get ( " zombietime " , " 2 " , FCVAR_SERVER , " timeout for clients-zombie (who died but not respawned) " ) ;
sv_pausable = Cvar_Get ( " pausable " , " 1 " , FCVAR_SERVER , " allow players to pause or not " ) ;
sv_allow_studio_attachment_angles = Cvar_Get ( " sv_allow_studio_attachment_angles " , " 0 " , FCVAR_ARCHIVE , " enable calc angles for attachment points (on studio models) " ) ;
sv_allow_rotate_pushables = Cvar_Get ( " sv_allow_rotate_pushables " , " 0 " , FCVAR_ARCHIVE , " let the pushers rotate pushables with included origin-brush " ) ;
sv_validate_changelevel = Cvar_Get ( " sv_validate_changelevel " , " 1 " , FCVAR_ARCHIVE , " test change level for level-designer errors " ) ;
Cvar_RegisterVariable ( & sv_clienttrace ) ;
Cvar_RegisterVariable ( & sv_bounce ) ;
Cvar_RegisterVariable ( & sv_spectatormaxspeed ) ;
Cvar_RegisterVariable ( & sv_waterfriction ) ;
Cvar_RegisterVariable ( & sv_wateraccelerate ) ;
Cvar_RegisterVariable ( & sv_rollangle ) ;
Cvar_RegisterVariable ( & sv_rollspeed ) ;
Cvar_RegisterVariable ( & sv_airaccelerate ) ;
Cvar_RegisterVariable ( & sv_maxvelocity ) ;
Cvar_RegisterVariable ( & sv_gravity ) ;
Cvar_RegisterVariable ( & sv_maxspeed ) ;
Cvar_RegisterVariable ( & sv_accelerate ) ;
Cvar_RegisterVariable ( & sv_friction ) ;
Cvar_RegisterVariable ( & sv_edgefriction ) ;
Cvar_RegisterVariable ( & sv_stopspeed ) ;
2017-02-13 22:00:00 +01:00
sv_maxclients = Cvar_Get ( " maxplayers " , " 1 " , FCVAR_LATCH | FCVAR_SERVER | FCVAR_UNLOGGED , " server max capacity " ) ;
2017-02-12 22:00:00 +01:00
sv_check_errors = Cvar_Get ( " sv_check_errors " , " 0 " , FCVAR_ARCHIVE , " check edicts for errors " ) ;
public_server = Cvar_Get ( " public " , " 0 " , FCVAR_SERVER , " change server type from private to public " ) ;
sv_lighting_modulate = Cvar_Get ( " r_lighting_modulate " , " 0.6 " , FCVAR_ARCHIVE , " lightstyles modulate scale " ) ;
sv_reconnect_limit = Cvar_Get ( " sv_reconnect_limit " , " 3 " , FCVAR_ARCHIVE , " max reconnect attempts " ) ;
Cvar_RegisterVariable ( & sv_failuretime ) ;
Cvar_RegisterVariable ( & sv_unlag ) ;
Cvar_RegisterVariable ( & sv_maxunlag ) ;
Cvar_RegisterVariable ( & sv_unlagpush ) ;
Cvar_RegisterVariable ( & sv_unlagsamples ) ;
Cvar_RegisterVariable ( & sv_allow_upload ) ;
Cvar_RegisterVariable ( & sv_allow_download ) ;
Cvar_RegisterVariable ( & sv_send_logos ) ;
Cvar_RegisterVariable ( & sv_send_resources ) ;
sv_sendvelocity = Cvar_Get ( " sv_sendvelocity " , " 1 " , FCVAR_ARCHIVE , " force to send velocity for event_t structure across network " ) ;
Cvar_RegisterVariable ( & sv_consistency ) ;
2010-12-09 22:00:00 +01:00
sv_novis = Cvar_Get ( " sv_novis " , " 0 " , 0 , " force to ignore server visibility " ) ;
2008-12-26 22:00:00 +01:00
2017-02-21 22:00:00 +01:00
Cvar_RegisterVariable ( & violence_ablood ) ;
Cvar_RegisterVariable ( & violence_hblood ) ;
Cvar_RegisterVariable ( & violence_agibs ) ;
Cvar_RegisterVariable ( & violence_hgibs ) ;
2017-02-12 22:00:00 +01:00
// when we in developer-mode automatically turn cheats on
if ( host . developer > 1 ) Cvar_SetValue ( " sv_cheats " , 1.0f ) ;
2010-03-25 22:00:00 +01:00
SV_ClearSaveDir ( ) ; // delete all temporary *.hl files
2016-11-14 22:00:00 +01:00
MSG_Init ( & net_message , " NetMessage " , net_message_buffer , sizeof ( net_message_buffer ) ) ;
2007-06-21 22:00:00 +02:00
}
/*
= = = = = = = = = = = = = = = = = =
SV_FinalMessage
Used by SV_Shutdown to send a final message to all
connected clients before the server goes down . The messages are sent immediately ,
not just stuck on the outgoing message list , because the server is going
to totally exit after returning from this function .
= = = = = = = = = = = = = = = = = =
*/
2010-10-26 22:00:00 +02:00
void SV_FinalMessage ( char * message , qboolean reconnect )
2007-06-21 22:00:00 +02:00
{
2008-07-09 22:00:00 +02:00
sv_client_t * cl ;
2011-04-05 22:00:00 +02:00
byte msg_buf [ 1024 ] ;
2010-08-06 22:00:00 +02:00
sizebuf_t msg ;
2008-07-12 22:00:00 +02:00
int i ;
2007-06-21 22:00:00 +02:00
2016-11-14 22:00:00 +01:00
MSG_Init ( & msg , " FinalMessage " , msg_buf , sizeof ( msg_buf ) ) ;
2017-02-05 22:00:00 +01:00
MSG_BeginServerCmd ( & msg , svc_print ) ;
2016-11-14 22:00:00 +01:00
MSG_WriteByte ( & msg , PRINT_HIGH ) ;
MSG_WriteString ( & msg , va ( " %s \n " , message ) ) ;
2007-06-21 22:00:00 +02:00
2008-07-12 22:00:00 +02:00
if ( reconnect )
2007-08-01 22:00:00 +02:00
{
2017-02-05 22:00:00 +01:00
MSG_BeginServerCmd ( & msg , svc_changing ) ;
2010-08-16 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
if ( sv . loadgame | | svs . maxclients > 1 | | sv . changelevel )
2016-11-14 22:00:00 +01:00
MSG_WriteOneBit ( & msg , 1 ) ; // changelevel
else MSG_WriteOneBit ( & msg , 0 ) ;
2007-08-01 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
else
2007-08-01 22:00:00 +02:00
{
2017-02-05 22:00:00 +01:00
MSG_BeginServerCmd ( & msg , svc_disconnect ) ;
2007-08-01 22:00:00 +02:00
}
2008-07-12 22:00:00 +02:00
2007-06-21 22:00:00 +02:00
// send it twice
// stagger the packets to crutch operating system limited buffers
2017-02-12 22:00:00 +01:00
for ( i = 0 , cl = svs . clients ; i < svs . maxclients ; i + + , cl + + )
2016-11-21 22:00:00 +01:00
if ( cl - > state > = cs_connected & & ! FBitSet ( cl - > flags , FCL_FAKECLIENT ) )
2016-11-14 22:00:00 +01:00
Netchan_Transmit ( & cl - > netchan , MSG_GetNumBytesWritten ( & msg ) , MSG_GetData ( & msg ) ) ;
2007-06-21 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
for ( i = 0 , cl = svs . clients ; i < svs . maxclients ; i + + , cl + + )
2016-11-21 22:00:00 +01:00
if ( cl - > state > = cs_connected & & ! FBitSet ( cl - > flags , FCL_FAKECLIENT ) )
2016-11-14 22:00:00 +01:00
Netchan_Transmit ( & cl - > netchan , MSG_GetNumBytesWritten ( & msg ) , MSG_GetData ( & msg ) ) ;
2007-06-21 22:00:00 +02:00
}
/*
= = = = = = = = = = = = = = = =
SV_Shutdown
Called when each game quits ,
before Sys_Quit or Sys_Error
= = = = = = = = = = = = = = = =
*/
2010-10-26 22:00:00 +02:00
void SV_Shutdown ( qboolean reconnect )
2007-06-21 22:00:00 +02:00
{
2007-10-29 22:00:00 +01:00
// already freed
2012-06-25 22:00:00 +02:00
if ( ! SV_Active ( ) ) return ;
2007-10-29 22:00:00 +01:00
2015-12-04 22:00:00 +01:00
// rcon will be disconnected
SV_EndRedirect ( ) ;
if ( host . type = = HOST_DEDICATED )
MsgDev ( D_INFO , " SV_Shutdown: %s \n " , host . finalmsg ) ;
if ( svs . clients )
SV_FinalMessage ( host . finalmsg , reconnect ) ;
2007-06-21 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
if ( public_server - > value & & svs . maxclients ! = 1 )
2015-12-04 22:00:00 +01:00
Master_Shutdown ( ) ;
2009-09-28 22:00:00 +02:00
if ( ! reconnect ) SV_UnloadProgs ( ) ;
else SV_DeactivateServer ( ) ;
2007-06-21 22:00:00 +02:00
// free current level
2016-11-17 22:00:00 +01:00
memset ( & sv , 0 , sizeof ( sv ) ) ;
2008-08-04 22:00:00 +02:00
Host_SetServerState ( sv . state ) ;
2007-06-21 22:00:00 +02:00
// free server static data
2010-10-15 22:00:00 +02:00
if ( svs . clients )
{
Z_Free ( svs . clients ) ;
svs . clients = NULL ;
}
if ( svs . baselines )
{
Z_Free ( svs . baselines ) ;
svs . baselines = NULL ;
}
if ( svs . packet_entities )
{
Z_Free ( svs . packet_entities ) ;
svs . packet_entities = NULL ;
svs . num_client_entities = 0 ;
svs . next_client_entities = 0 ;
}
2012-12-18 21:00:00 +01:00
2010-10-15 22:00:00 +02:00
svs . initialized = false ;
2009-01-02 22:00:00 +01:00
}