/* * SV_KillServer_f * Kick everyone off, possibly in preparation for a new game */ static void SV_KillServer_f( void ) { if( !svs.initialized ) return; SV_ShutdownGame( "Server was killed", qfalse ); }
/* * SV_Frame */ void SV_Frame( int realmsec, int gamemsec ) { const unsigned int wrappingPoint = 0x70000000; time_before_game = time_after_game = 0; // if server is not active, do nothing if( !svs.initialized ) { SV_CheckDefaultMap(); return; } svs.realtime += realmsec; svs.gametime += gamemsec; // advance to next map if the server is running for too long (numbers taken from q3 src) if( svs.realtime > wrappingPoint || svs.gametime > wrappingPoint || sv.framenum >= wrappingPoint ) { Cbuf_AddText( "wait; vstr nextmap\n" ); SV_ShutdownGame( "Restarting server due to time wrapping", qtrue ); return; } // check timeouts SV_CheckTimeouts(); // get packets from clients SV_ReadPackets(); // let everything in the world think and move if( SV_RunGameFrame( gamemsec ) ) { // send messages back to the clients that had packets read this frame SV_SendClientMessages(); // write snap to server demo file SV_Demo_WriteSnap(); // run matchmaker stuff SV_CheckMatchUUID(); SV_MM_Frame(); // send a heartbeat to the master if needed SV_MasterHeartbeat(); // clear teleport flags, etc for next frame ge->ClearSnap(); } SV_CheckAutoUpdate(); }
/* * SV_Shutdown * * Called once when the program is shutting down */ void SV_Shutdown( const char *finalmsg ) { if( !sv_initialized ) return; ML_Shutdown(); SV_MM_Shutdown( qtrue ); SV_ShutdownGame( finalmsg, qfalse ); SV_ShutdownOperatorCommands(); Mem_FreePool( &sv_mempool ); sv_initialized = qfalse; }
/* * Com_Error * * Both client and server can use this, and it will * do the apropriate things. */ void Com_Error( com_error_code_t code, const char *format, ... ) { va_list argptr; char *msg = com_errormsg; const size_t sizeof_msg = sizeof( com_errormsg ); static qboolean recursive = qfalse; if( recursive ) { Com_Printf( "recursive error after: %s", msg ); // wsw : jal : log it Sys_Error( "recursive error after: %s", msg ); } recursive = qtrue; va_start( argptr, format ); Q_vsnprintfz( msg, sizeof_msg, format, argptr ); va_end( argptr ); if( code == ERR_DROP ) { Com_Printf( "********************\nERROR: %s\n********************\n", msg ); SV_ShutdownGame( va( "Server crashed: %s\n", msg ), qfalse ); CL_Disconnect( msg ); recursive = qfalse; longjmp( abortframe, -1 ); } else { Com_Printf( "********************\nERROR: %s\n********************\n", msg ); SV_Shutdown( va( "Server fatal crashed: %s\n", msg ) ); CL_Shutdown(); MM_Shutdown(); } if( log_file ) { FS_FCloseFile( log_file ); log_file = 0; } Sys_Error( "%s", msg ); }
/* * SV_InitGame * A brand new game has been started */ void SV_InitGame( void ) { int i; edict_t *ent; netadr_t address, ipv6_address; // make sure the client is down CL_Disconnect( NULL ); SCR_BeginLoadingPlaque(); if( svs.initialized ) { // cause any connected clients to reconnect SV_ShutdownGame( "Server restarted", qtrue ); // SV_ShutdownGame will also call Cvar_GetLatchedVars } else { // get any latched variable changes (sv_maxclients, etc) Cvar_GetLatchedVars( CVAR_LATCH ); } svs.initialized = qtrue; if( sv_skilllevel->integer > 2 ) Cvar_ForceSet( "sv_skilllevel", "2" ); if( sv_skilllevel->integer < 0 ) Cvar_ForceSet( "sv_skilllevel", "0" ); // init clients if( sv_maxclients->integer < 1 ) Cvar_FullSet( "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH, qtrue ); else if( sv_maxclients->integer > MAX_CLIENTS ) Cvar_FullSet( "sv_maxclients", va( "%i", MAX_CLIENTS ), CVAR_SERVERINFO | CVAR_LATCH, qtrue ); svs.spawncount = rand(); svs.clients = Mem_Alloc( sv_mempool, sizeof( client_t )*sv_maxclients->integer ); svs.client_entities.num_entities = sv_maxclients->integer * UPDATE_BACKUP * MAX_SNAP_ENTITIES; svs.client_entities.entities = Mem_Alloc( sv_mempool, sizeof( entity_state_t ) * svs.client_entities.num_entities ); // init network stuff address.type = NA_NOTRANSMIT; ipv6_address.type = NA_NOTRANSMIT; if( !dedicated->integer ) { NET_InitAddress( &address, NA_LOOPBACK ); if( !NET_OpenSocket( &svs.socket_loopback, SOCKET_LOOPBACK, &address, qtrue ) ) Com_Error( ERR_FATAL, "Couldn't open loopback socket: %s\n", NET_ErrorString() ); } if( dedicated->integer || sv_maxclients->integer > 1 ) { qboolean socket_opened = qfalse; // IPv4 NET_StringToAddress( sv_ip->string, &address ); NET_SetAddressPort( &address, sv_port->integer ); if( !NET_OpenSocket( &svs.socket_udp, SOCKET_UDP, &address, qtrue ) ) Com_Printf( "Error: Couldn't open UDP socket: %s\n", NET_ErrorString() ); else socket_opened = qtrue; // IPv6 NET_StringToAddress( sv_ip6->string, &ipv6_address ); if( ipv6_address.type == NA_IP6 ) { NET_SetAddressPort( &ipv6_address, sv_port6->integer ); if( !NET_OpenSocket( &svs.socket_udp6, SOCKET_UDP, &ipv6_address, qtrue ) ) Com_Printf( "Error: Couldn't open UDP6 socket: %s\n", NET_ErrorString() ); else socket_opened = qtrue; } else Com_Printf( "Error: invalid IPv6 address: %s\n", sv_ip6->string ); if( dedicated->integer && !socket_opened ) Com_Error( ERR_FATAL, "Couldn't open any socket\n" ); } #ifdef TCP_ALLOW_CONNECT if( sv_tcp->integer && ( dedicated->integer || sv_maxclients->integer > 1 ) ) { if( !NET_OpenSocket( &svs.socket_tcp, SOCKET_TCP, &address, qtrue ) ) { Com_Printf( "Error: Couldn't open TCP socket: %s", NET_ErrorString() ); Cvar_ForceSet( "sv_tcp", "0" ); } else { if( !NET_Listen( &svs.socket_tcp ) ) { Com_Printf( "Error: Couldn't listen to TCP socket: %s", NET_ErrorString() ); NET_CloseSocket( &svs.socket_tcp ); Cvar_ForceSet( "sv_tcp", "0" ); } } } #endif // init mm // SV_MM_Init(); // init game SV_InitGameProgs(); for( i = 0; i < sv_maxclients->integer; i++ ) { ent = EDICT_NUM( i+1 ); ent->s.number = i+1; svs.clients[i].edict = ent; } // load the map assert( !svs.cms ); svs.cms = CM_New( NULL ); }