Beispiel #1
0
/*
=================
SV_SendServerCommand

Sends a reliable command string to be interpreted by
the client game module: "cp", "print", "chat", etc
A NULL client will broadcast to all clients
=================
*/
void SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
	va_list		argptr;
	byte		message[MAX_MSGLEN];
	client_t	*client;
	int			j;

	message[0] = svc_serverCommand;

	va_start (argptr,fmt);
	Q_vsnprintf( (char *)message+1, sizeof(message)-1, fmt, argptr );
	va_end (argptr);

	// Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
	// The actual cause of the bug is probably further downstream
	// and should maybe be addressed later, but this certainly
	// fixes the problem for now
	if ( strlen ((char *)message+1) > 1022 ) {
		return;
	}

	if ( cl != NULL ) {
		SV_AddServerCommand( cl, (char *)message );
		return;
	}

	// send the data to all relevent clients
	for (j = 0, client = svs.clients; j < 1 ; j++, client++) {
		if ( client->state < CS_PRIMED ) {
			continue;
		}
		SV_AddServerCommand( client, (char *)message );
	}
}
Beispiel #2
0
/*
=================
SV_SendServerCommand

Sends a reliable command string to be interpreted by 
the client game module: "cp", "print", "chat", etc
A NULL client will broadcast to all clients
=================
*/
void SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
	va_list		argptr;
	byte		message[MAX_MSGLEN];
	int			len;
	client_t	*client;
	int			j;
	
	message[0] = svc_serverCommand;

	va_start (argptr,fmt);
	vsprintf ((char *)message+1, fmt,argptr);
	va_end (argptr);
	len = strlen( (char *)message ) + 1;

	if ( cl != NULL ) {
		SV_AddServerCommand( cl, (char *)message );
		return;
	}

	// send the data to all relevent clients
	for (j = 0, client = svs.clients; j < 1 ; j++, client++) {
		if ( client->state < CS_PRIMED ) {
			continue;
		}
		SV_AddServerCommand( client, (char *)message );
	}
}
Beispiel #3
0
/*
=================
SV_SendServerCommand

Sends a reliable command string to be interpreted by
the client game module: "cp", "print", "chat", etc
A NULL client will broadcast to all clients
=================
*/
void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ... ) {
	va_list argptr;
	byte message[MAX_MSGLEN];
	client_t    *client;
	int j;

	va_start( argptr,fmt );
	vsprintf( (char *)message, fmt,argptr );
	va_end( argptr );

	if ( cl != NULL ) {
		SV_AddServerCommand( cl, (char *)message );
		return;
	}

	// hack to echo broadcast prints to console
	if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5 ) ) {
		Com_Printf( "broadcast: %s\n", SV_ExpandNewlines( (char *)message ) );
	}

	// send the data to all relevent clients
	for ( j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++ ) {
		if ( client->state < CS_PRIMED ) {
			continue;
		}
		// Ridah, don't need to send messages to AI
		if ( client->gentity && client->gentity->r.svFlags & SVF_CASTAI ) {
			continue;
		}
		// done.
		SV_AddServerCommand( client, (char *)message );
	}
}
Beispiel #4
0
/*
=================
SV_SendServerCommand

Sends a reliable command string to be interpreted by
the client game module: "cp", "print", "chat", etc
A nullptr client will broadcast to all clients
=================
*/
void QDECL PRINTF_LIKE(2) SV_SendServerCommand( client_t *cl, const char *fmt, ... )
{
	va_list  argptr;
	byte     message[ MAX_MSGLEN ];
	client_t *client;
	int      j;

	va_start( argptr, fmt );
	Q_vsnprintf( ( char * ) message, sizeof( message ), fmt, argptr );
	va_end( argptr );

	// do not forward server command messages that would be too big to clients
	// ( q3infoboom / q3msgboom stuff )
	if ( strlen( ( char * ) message ) > 1022 )
	{
		return;
	}

	if ( cl != nullptr )
	{
		SV_AddServerCommand( cl, ( char * ) message );
		return;
	}

	if ( Com_IsDedicatedServer() )
	{
		if ( !strncmp( ( char * ) message, "print_tr_p ", 11 ) )
		{
			SV_PrintTranslatedText( ( const char * ) message, true, true );
		}
		else if ( !strncmp( ( char * ) message, "print_tr ", 9 ) )
		{
			SV_PrintTranslatedText( ( const char * ) message, true, false );
		}

		// hack to echo broadcast prints to console
		else if ( !strncmp( ( char * ) message, "print ", 6 ) )
		{
			Com_Printf( "Broadcast: %s", Cmd_UnquoteString( ( char * ) message + 6 ) );
		}
	}

	// send the data to all relevent clients
	for ( j = 0, client = svs.clients; j < sv_maxclients->integer; j++, client++ )
	{
		if ( client->state < CS_PRIMED )
		{
			continue;
		}

		// Ridah, don't need to send messages to AI
		if ( SV_IsBot(client) )
		{
			continue;
		}

		// done.
		SV_AddServerCommand( client, ( char * ) message );
	}
}
Beispiel #5
0
/*
* SV_SendServerCommand
* 
* Sends a reliable command string to be interpreted by
* the client: "cs", "changing", "disconnect", etc
* A NULL client will broadcast to all clients
*/
void SV_SendServerCommand( client_t *cl, const char *format, ... )
{
	va_list	argptr;
	char message[MAX_MSGLEN];
	client_t *client;
	int i;

	va_start( argptr, format );
	Q_vsnprintfz( message, sizeof( message ), format, argptr );
	va_end( argptr );

	if( cl != NULL )
	{
		if( cl->state < CS_CONNECTING )
			return;
		SV_AddServerCommand( cl, message );
		return;
	}

	// send the data to all relevant clients
	for( i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++ )
	{
		if( client->state < CS_CONNECTING )
			continue;
		SV_AddServerCommand( client, message );
	}

	// add to demo
	if( svs.demo.file )
		SV_AddServerCommand( &svs.demo.client, message );
}
/*
=================
SV_SendServerCommand

Sends a reliable command string to be interpreted by
the client game module: "cp", "print", "chat", etc
A NULL client will broadcast to all clients
=================
*/
void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
	va_list		argptr;
	byte		message[MAX_MSGLEN];
	client_t	*client;
	int			j;
	
	va_start (argptr,fmt);
	Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr);
	va_end (argptr);

	// Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
	// The actual cause of the bug is probably further downstream
	// and should maybe be addressed later, but this certainly
	// fixes the problem for now
	if ( strlen ((char *)message) > 1022 ) {
		return;
	}

	if ( cl != NULL ) {
		SV_AddServerCommand( cl, (char *)message );
		return;
	}

	// hack to echo broadcast prints to console
	if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) {
		Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) );
	}

	// send the data to all relevent clients
	for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) {
		SV_AddServerCommand( client, (char *)message );
	}
}
Beispiel #7
0
/*
=================
SV_SendServerCommand

Sends a reliable command string to be interpreted by 
the client game module: "cp", "print", "chat", etc
A NULL client will broadcast to all clients
=================
*/
void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
	va_list		argptr;
	byte		message[MAX_MSGLEN];
	client_t	*client;
	int			j;
	int			msglen;
	
	va_start (argptr,fmt);
	Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr);
	va_end (argptr);

	msglen = strlen((char *)message);

	// Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
	// The actual cause of the bug is probably further downstream
	// and should maybe be addressed later, but this certainly
	// fixes the problem for now
	if ( msglen > 1022 ) {
		return;
	}

	if (sv.incognitoJoinSpec &&
			cl == NULL &&
			(!Q_strncmp((char *) message, "print \"", 7)) &&
			msglen >= 27 + 7 &&
			!strcmp("^7 joined the spectators.\n\"", ((char *) message) + msglen - 27)) {
		return;
	}

	/////////////////////////////////////////////////////////
	// separator for incognito.patch and specchatglobal.patch
	/////////////////////////////////////////////////////////

	if (sv_specChatGlobal->integer > 0 && cl != NULL &&
			!Q_strncmp((char *) message, "chat \"^7(SPEC) ", 15)) {
		if (!Q_strncmp((char *) message, sv.lastSpecChat, sizeof(sv.lastSpecChat) - 1)) {
			return;
		}
		Q_strncpyz(sv.lastSpecChat, (char *) message, sizeof(sv.lastSpecChat));
		cl = NULL;
	}

	if ( cl != NULL ) {
		SV_AddServerCommand( cl, (char *)message );
		return;
	}

	// hack to echo broadcast prints to console
	if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) {
		Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) );
	}

	// send the data to all relevent clients
	for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) {
		SV_AddServerCommand( client, (char *)message );
	}
}
Beispiel #8
0
/**
 * @brief Sends a reliable command string to be interpreted by the client game
 * module: "cp", "print", "chat", etc
 *
 * A NULL client will broadcast to all clients
 */
void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...)
{
	va_list  argptr;
	byte     message[MAX_MSGLEN];
	client_t *client;
	int      j;

	va_start(argptr, fmt);
	Q_vsnprintf((char *)message, sizeof(message), fmt, argptr);
	va_end(argptr);

	// do not forward server command messages that would be too big to clients
	// ( q3infoboom / q3msgboom stuff )
	// see http://aluigi.altervista.org/adv/q3msgboom-adv.txt
	if (strlen((char *)message) > 1022)
	{
		SV_WriteAttackLog("Warning: q3infoboom/q3msgboom exploit attack.\n"); // FIXME: add client slot
		return;
	}

	if (cl != NULL)
	{
		SV_AddServerCommand(cl, (char *)message);
		return;
	}

	// hack to echo broadcast prints to console
	if (com_dedicated->integer && !strncmp((char *)message, "print", 5))
	{
		Com_Printf("broadcast: %s\n", SV_ExpandNewlines((char *)message));
	}

	// send the data to all relevent clients
	for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++)
	{
		if (client->state < CS_PRIMED)
		{
			continue;
		}
		// don't need to send messages to AI
		if (client->gentity && (client->gentity->r.svFlags & SVF_BOT))
		{
			continue;
		}

		SV_AddServerCommand(client, (char *)message);
	}
}
/*
=================
SV_SendServerCommand

Sends a reliable command string to be interpreted by
the client game module: "cp", "print", "chat", etc
A NULL client will broadcast to all clients
=================
*/
void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
	va_list		argptr;
	byte		message[MAX_MSGLEN];
	client_t	*client;
	int			j;

	va_start (argptr,fmt);
	Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr);
	va_end (argptr);

	// Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
	// The actual cause of the bug is probably further downstream
	// and should maybe be addressed later, but this certainly
	// fixes the problem for now
	if ( strlen ((char *)message) > 1022 ) {
		return;
	}

	if ( cl != NULL ) {
		SV_AddServerCommand( cl, (char *)message );
		return;
	}

	// hack to echo broadcast prints to console
	if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) {
		Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) );
	}

	// save broadcasts to demo
	// note: in the case a command is only issued to a specific client, it is NOT recorded (see above when cl != NULL). If you want to record them, just place this code above, but be warned that it may be dangerous (such as "disconnect" command) because server commands will be replayed to every connected clients!
	if ( sv.demoState == DS_RECORDING ) {
		SV_DemoWriteServerCommand( (char *)message );
	}

	// send the data to all relevent clients
	for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) {
		SV_AddServerCommand( client, (char *)message );
	}
}
Beispiel #10
0
/*
=================
SV_SendServerCommand

Sends a reliable command string to be interpreted by
the client game module: "cp", "print", "chat", etc
A NULL client will broadcast to all clients
=================
*/
void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ... ) {
	va_list argptr;
	byte message[MAX_MSGLEN];
	client_t    *client;
	int j;

	va_start( argptr,fmt );

#if defined RTCW_SP
	vsprintf( (char *)message, fmt,argptr );
#else
	Q_vsnprintf( (char *)message, sizeof( message ), fmt, argptr );
#endif // RTCW_XX

	va_end( argptr );

#if !defined RTCW_SP
	// do not forward server command messages that would be too big to clients
	// ( q3infoboom / q3msgboom stuff )
	if ( strlen( (char *)message ) > 1022 ) {
		return;
	}
#endif // RTCW_XX

	if ( cl != NULL ) {
		SV_AddServerCommand( cl, (char *)message );
		return;
	}

	// hack to echo broadcast prints to console
	if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5 ) ) {
		Com_Printf( "broadcast: %s\n", SV_ExpandNewlines( (char *)message ) );
	}

	// send the data to all relevent clients
	for ( j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++ ) {
		if ( client->state < CS_PRIMED ) {
			continue;
		}
		// Ridah, don't need to send messages to AI

#if !defined RTCW_ET
		if ( client->gentity && client->gentity->r.svFlags & SVF_CASTAI ) {
#else
		if ( client->gentity && client->gentity->r.svFlags & SVF_BOT ) {
#endif // RTCW_XX

			continue;
		}
		// done.
		SV_AddServerCommand( client, (char *)message );
	}
}


/*
==============================================================================

MASTER SERVER FUNCTIONS

==============================================================================
*/

/*
================
SV_MasterHeartbeat

Send a message to the masters every few minutes to
let it know we are alive, and log information.
We will also have a heartbeat sent when a server
changes from empty to non-empty, and full to non-full,
but not on every player enter or exit.
================
*/
#define HEARTBEAT_MSEC  300 * 1000

#if !defined RTCW_ET
#define HEARTBEAT_GAME  "Wolfenstein-1"
#else
//#define	HEARTBEAT_GAME	"Wolfenstein-1"
//#define	HEARTBEAT_DEAD	"WolfFlatline-1"			// NERVE - SMF
#define HEARTBEAT_GAME  "EnemyTerritory-1"
#endif // RTCW_XX

#if defined RTCW_SP
void SV_MasterHeartbeat( void ) {
#else

#if !defined RTCW_ET
#define HEARTBEAT_DEAD  "WolfFlatline-1"         // NERVE - SMF
#else
#define HEARTBEAT_DEAD  "ETFlatline-1"           // NERVE - SMF
#endif // RTCW_XX

void SV_MasterHeartbeat( const char *hbname ) {
#endif // RTCW_XX

	static netadr_t adr[MAX_MASTER_SERVERS];
	int i;

#if defined RTCW_MP
	// DHM - Nerve :: Update Server doesn't send heartbeat
#ifdef UPDATE_SERVER
	return;
#endif
#endif // RTCW_XX

#if defined RTCW_ET
	if ( SV_GameIsSinglePlayer() ) {
		return;     // no heartbeats for SP
	}
#endif // RTCW_XX

	// "dedicated 1" is for lan play, "dedicated 2" is for inet public play
	if ( !com_dedicated || com_dedicated->integer != 2 ) {
		return;     // only dedicated servers send heartbeats
	}

	// if not time yet, don't send anything
	if ( svs.time < svs.nextHeartbeatTime ) {
		return;
	}
	svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;


	// send to group masters
	for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) {
		if ( !sv_master[i]->string[0] ) {
			continue;
		}

		// see if we haven't already resolved the name
		// resolving usually causes hitches on win95, so only
		// do it when needed
		if ( sv_master[i]->modified ) {
			sv_master[i]->modified = qfalse;

			Com_Printf( "Resolving %s\n", sv_master[i]->string );
			if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) {
				// if the address failed to resolve, clear it
				// so we don't take repeated dns hits
				Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string );
				Cvar_Set( sv_master[i]->name, "" );
				sv_master[i]->modified = qfalse;
				continue;
			}
			if ( !strstr( ":", sv_master[i]->string ) ) {
				adr[i].port = rtcw::Endian::be( PORT_MASTER );
			}
			Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", sv_master[i]->string,
						adr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3],
						rtcw::Endian::be( adr[i].port ) );
		}


		Com_Printf( "Sending heartbeat to %s\n", sv_master[i]->string );
		// this command should be changed if the server info / status format
		// ever incompatably changes

#if defined RTCW_SP
		NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", HEARTBEAT_GAME );
#else
		NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", hbname );
#endif // RTCW_XX

	}
}

#if !defined RTCW_SP
/*
=================
SV_MasterGameCompleteStatus

NERVE - SMF - Sends gameCompleteStatus messages to all master servers
=================
*/
void SV_MasterGameCompleteStatus() {
	static netadr_t adr[MAX_MASTER_SERVERS];
	int i;

#if defined RTCW_ET
	if ( SV_GameIsSinglePlayer() ) {
		return;     // no master game status for SP
	}
#endif // RTCW_XX

	// "dedicated 1" is for lan play, "dedicated 2" is for inet public play
	if ( !com_dedicated || com_dedicated->integer != 2 ) {
		return;     // only dedicated servers send master game status
	}

	// send to group masters
	for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) {
		if ( !sv_master[i]->string[0] ) {
			continue;
		}

		// see if we haven't already resolved the name
		// resolving usually causes hitches on win95, so only
		// do it when needed
		if ( sv_master[i]->modified ) {
			sv_master[i]->modified = qfalse;

			Com_Printf( "Resolving %s\n", sv_master[i]->string );
			if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) {
				// if the address failed to resolve, clear it
				// so we don't take repeated dns hits
				Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string );
				Cvar_Set( sv_master[i]->name, "" );
				sv_master[i]->modified = qfalse;
				continue;
			}
			if ( !strstr( ":", sv_master[i]->string ) ) {
				adr[i].port = rtcw::Endian::be ( PORT_MASTER );
			}
			Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", sv_master[i]->string,
						adr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3],
						rtcw::Endian::be ( adr[i].port ) );
		}

		Com_Printf( "Sending gameCompleteStatus to %s\n", sv_master[i]->string );
		// this command should be changed if the server info / status format
		// ever incompatably changes
		SVC_GameCompleteStatus( adr[i] );
	}
}
#endif // RTCW_XX

/*
=================
SV_MasterShutdown

Informs all masters that this server is going down
=================
*/
void SV_MasterShutdown( void ) {
	// send a hearbeat right now
	svs.nextHeartbeatTime = -9999;

#if defined RTCW_SP
	SV_MasterHeartbeat();
#else
	SV_MasterHeartbeat( HEARTBEAT_DEAD );               // NERVE - SMF - changed to flatline
#endif // RTCW_XX

	// send it again to minimize chance of drops

#if defined RTCW_SP
	svs.nextHeartbeatTime = -9999;
	SV_MasterHeartbeat();
#else
//	svs.nextHeartbeatTime = -9999;
//	SV_MasterHeartbeat( HEARTBEAT_DEAD );
#endif // RTCW_XX

	// when the master tries to poll the server, it won't respond, so
	// it will be removed from the list
}
Beispiel #11
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f( void ) {
	int			i;
	client_t	*client;
	char		*denied;
	qboolean	isBot;
	int			delay;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId ) {
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( sv.restartTime ) {
		return;
	}

	if (Cmd_Argc() > 1 ) {
		delay = atoi( Cmd_Argv(1) );
	}
	else {
		delay = 5;
	}
	if( delay && (!Cvar_VariableValue("g_doWarmup") || Cvar_VariableValue("g_gametype") == GT_TOURNAMENT) ) {
		sv.restartTime = svs.time + delay * 1000;
		SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) );
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified || sv_gametype->modified ) {
		char	mapname[MAX_QPATH];

		Com_Printf( "variable change -- restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );

		SV_SpawnServer( mapname, qfalse, eForceReload_NOTHING );
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	sv.restartedServerId = sv.serverId;
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0 ;i < 3 ; i++ ) {
		VM_Call( gvm, GAME_RUN_FRAME, svs.time );
		svs.time += 100;
	}

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for (i=0 ; i<sv_maxclients->integer ; i++) {
		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if ( client->state < CS_CONNECTED) {
			continue;
		}

		if ( client->netchan.remoteAddress.type == NA_BOT ) {
			isBot = qtrue;
		} else {
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = (char *)VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );
		if ( denied ) {
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, denied );
			Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i ); // bk010125
			continue;
		}

		client->state = CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}

	// run another frame to allow things to look at all the players
	VM_Call( gvm, GAME_RUN_FRAME, svs.time );
	svs.time += 100;
}
Beispiel #12
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f( void )
{
	int         i;
	client_t    *client;
	char        *denied;
	qboolean    isBot;
	int         delay = 0;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId )
	{
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Com_Printf(_( "Server is not running.\n" ));
		return;
	}

	// ydnar: allow multiple delayed server restarts [atvi bug 3813]
	//% if ( sv.restartTime ) {
	//%     return;
	//% }

	if ( Cmd_Argc() > 1 )
	{
		delay = atoi( Cmd_Argv( 1 ) );
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified )
	{
		char mapname[ MAX_QPATH ];

		Com_Printf(_( "sv_maxclients variable change — restarting.\n" ));
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );

		SV_SpawnServer( mapname );
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );

	// reset all the VM data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	Cvar_Set( "sv_serverRestarting", "1" );

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0; i < GAME_INIT_FRAMES; i++ )
	{
		VM_Call( gvm, GAME_RUN_FRAME, svs.time );
		svs.time += FRAMETIME;
	}

	// create a baseline for more efficient communications
	// Gordon: meh, this won't work here as the client doesn't know it has happened
//  SV_CreateBaseline ();

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for ( i = 0; i < sv_maxclients->integer; i++ )
	{
		client = &svs.clients[ i ];

		// send the new gamestate to all connected clients
		if ( client->state < CS_CONNECTED )
		{
			continue;
		}

		if ( client->netchan.remoteAddress.type == NA_BOT )
		{
			isBot = qtrue;
		}
		else
		{
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );

		if ( denied )
		{
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, denied );

			if ( !isBot )
			{
				Com_Printf( "SV_MapRestart_f(%d): dropped client %i: denied!\n", delay, i );  // bk010125
			}

			continue;
		}

		client->state = CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}

	// run another frame to allow things to look at all the players
	VM_Call( gvm, GAME_RUN_FRAME, svs.time );
	svs.time += FRAMETIME;

	Cvar_Set( "sv_serverRestarting", "0" );
}
Beispiel #13
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f( void ) {
	int i;
	client_t    *client;
	char        *denied;
	qboolean isBot;
	int delay = 0;
	gamestate_t new_gs, old_gs;     // NERVE - SMF
	int worldspawnflags;            // DHM - Nerve
	int nextgt;                     // DHM - Nerve
	sharedEntity_t  *world;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId ) {
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( sv.restartTime ) {
		return;
	}

	// DHM - Nerve :: Check for invalid gametype
	sv_gametype = Cvar_Get( "g_gametype", "5", CVAR_SERVERINFO | CVAR_LATCH );
	nextgt = sv_gametype->integer;

	world = SV_GentityNum( ENTITYNUM_WORLD );
	worldspawnflags = world->r.worldflags;
	if  (
		( nextgt == GT_WOLF && ( worldspawnflags & 1 ) ) ||
		( nextgt == GT_WOLF_STOPWATCH && ( worldspawnflags & 2 ) ) ||
		( ( nextgt == GT_WOLF_CP || nextgt == GT_WOLF_CPH ) && ( worldspawnflags & 4 ) )
		) {

		if ( !( worldspawnflags & 1 ) ) {
			Cvar_Set( "g_gametype", "5" );
		} else {
			Cvar_Set( "g_gametype", "7" );
		}

		sv_gametype = Cvar_Get( "g_gametype", "5", CVAR_SERVERINFO | CVAR_LATCH );
	}
	// dhm

	if ( Cmd_Argc() > 1 ) {
		delay = atoi( Cmd_Argv( 1 ) );
	}

	if ( delay ) {
		sv.restartTime = svs.time + delay * 1000;
		SV_SetConfigstring( CS_WARMUP, va( "%i", sv.restartTime ) );
		return;
	}

	// NERVE - SMF - read in gamestate or just default to GS_PLAYING
	old_gs = atoi( Cvar_VariableString( "gamestate" ) );

	if ( Cmd_Argc() > 2 ) {
		new_gs = atoi( Cmd_Argv( 2 ) );
	} else {
		new_gs = GS_PLAYING;
	}

	if ( !SV_TransitionGameState( new_gs, old_gs, delay ) ) {
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified ) {
		char mapname[MAX_QPATH];

		Com_Printf( "sv_maxclients variable change -- restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );

		SV_SpawnServer( mapname, qfalse );
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	Cvar_Set( "sv_serverRestarting", "1" );

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0 ; i < 3 ; i++ ) {
		VM_Call( gvm, GAME_RUN_FRAME, svs.time );
		svs.time += 100;
	}

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if ( client->state < CS_CONNECTED ) {
			continue;
		}

		if ( client->netchan.remoteAddress.type == NA_BOT ) {
			isBot = qtrue;
		} else {
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );
		if ( denied ) {
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, denied );
			Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i ); // bk010125
			continue;
		}

		client->state = CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}

	// run another frame to allow things to look at all the players
	VM_Call( gvm, GAME_RUN_FRAME, svs.time );
	svs.time += 100;

	Cvar_Set( "sv_serverRestarting", "0" );
}
Beispiel #14
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f(void) {
	int             i, delay = 0;
	client_t       *client;
	char           *denied;
	qboolean        isBot;
	gamestate_t     new_gs, old_gs;	// NERVE - SMF

	// make sure we aren't restarting twice in the same frame
	if(com_frameTime == sv.serverId) {
		return;
	}

	// make sure server is running
	if(!com_sv_running->integer) {
		Com_Printf("Server is not running.\n");
		return;
	}

	if(Cmd_Argc() > 1) {
		delay = atoi(Cmd_Argv(1));
	}

	if(delay) {
		sv.restartTime = svs.time + delay * 1000;
		SV_SetConfigstring(CS_WARMUP, va("%i", sv.restartTime));
		return;
	}

	// NERVE - SMF - read in gamestate or just default to GS_PLAYING
	old_gs = (gamestate_t)atoi(Cvar_VariableString("gamestate"));

	if(SV_GameIsSinglePlayer() || SV_GameIsCoop()) {
		new_gs = GS_PLAYING;
	} else {
		if(Cmd_Argc() > 2) {
			new_gs = (gamestate_t)atoi(Cmd_Argv(2));
		} else {
			new_gs = GS_PLAYING;
		}
	}

	if(!SV_TransitionGameState(new_gs, old_gs, delay)) {
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if(sv_maxclients->modified) {
		char mapname[MAX_QPATH];

		Com_Printf("sv_maxclients variable change -- restarting.\n");
		// restart the map the slow way
		Q_strncpyz(mapname, Cvar_VariableString("mapname"), sizeof(mapname));

		SV_SpawnServer(mapname, qfalse);
		return;
	}

	// Check for loading a saved game
	if(Cvar_VariableIntegerValue("savegame_loading")) {
		// open the current savegame, and find out what the time is, everything else we can ignore
		char    savemap[MAX_QPATH], *cl_profileStr = Cvar_VariableString("cl_profile");
		byte    *buffer;
		int     size, savegameTime;

		if(com_gameInfo.usesProfiles) {
			Com_sprintf(savemap, sizeof(savemap), "profiles/%s/save/current.sav", cl_profileStr);
		} else {
			Q_strncpyz(savemap, "save/current.sav", sizeof(savemap));
		}

		size = FS_ReadFile(savemap, NULL);
		if(size < 0) {
			Com_Printf("Can't find savegame %s\n", savemap);
			return;
		}

		//buffer = Hunk_AllocateTempMemory(size);
		FS_ReadFile(savemap, (void **)&buffer);

		// the mapname is at the very start of the savegame file
		savegameTime = *(int *)(buffer + sizeof(int) + MAX_QPATH);

		if(savegameTime >= 0) {
			svs.time = savegameTime;
		}

		Hunk_FreeTempMemory(buffer);
	}
	// done.

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set("sv_serverid", va("%i", sv.serverId));

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	Cvar_Set("sv_serverRestarting", "1");

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for(i = 0; i < GAME_INIT_FRAMES; i++)
	{
		VM_Call(gvm, GAME_RUN_FRAME, svs.time);
		svs.time += FRAMETIME;
	}

	// create a baseline for more efficient communications
	// Gordon: meh, this wont work here as the client doesn't know it has happened
//  SV_CreateBaseline ();

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for(i = 0; i < sv_maxclients->integer; i++) {
		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if(client->state < CS_CONNECTED) {
			continue;
		}

		if(client->netchan.remoteAddress.type == NA_BOT) {
			if(SV_GameIsSinglePlayer() || SV_GameIsCoop()) {
				continue;		// dont carry across bots in single player
			}
			isBot = qtrue;
		} else {
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand(client, "map_restart\n");

		// connect the client again, without the firstTime flag
		denied = (char*)VM_ExplicitArgPtr(gvm, VM_Call(gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot));
		if(denied)
		{
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient(client, denied);
			if((!SV_GameIsSinglePlayer()) || (!isBot)) {
				Com_Printf("SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i);	// bk010125
			}
			continue;
		}

		client->state = CS_ACTIVE;

		SV_ClientEnterWorld(client, &client->lastUsercmd);
	}

	// run another frame to allow things to look at all the players
	VM_Call(gvm, GAME_RUN_FRAME, svs.time);
	svs.time += FRAMETIME;

	Cvar_Set("sv_serverRestarting", "0");
}
Beispiel #15
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f( void ) {
	int			i;
	client_t	*client;
	char		*denied;
	int			delay;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId ) {
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( sv.restartTime ) {
		return;
	}

	if (Cmd_Argc() > 1 ) {
		delay = atoi( Cmd_Argv(1) );
	}
	else {
		delay = 5;
	}
	if( delay && !Cvar_VariableValue("g_doWarmup") ) {
		sv.restartTime = sv.time + delay * 1000;
		SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) );
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified ) {
		char	mapname[MAX_QPATH];

		Com_Printf( "variable change -- restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );

		SV_SpawnServer( mapname, qfalse );
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid	
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );

	// if a map_restart occurs while a client is changing maps, we need
	// to give them the correct time so that when they finish loading
	// they don't violate the backwards time check in cl_cgame.c
	for (i=0 ; i<sv_maxclients->integer ; i++) {
		if (svs.clients[i].state == CS_PRIMED) {
			svs.clients[i].oldServerTime = sv.restartTime;
		}
	}

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for (i = 0; i < 3; i++)
	{
		VM_Call (gvm, GAME_RUN_FRAME, sv.time);
		sv.time += 100;
		svs.time += 100;
	}

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for (i=0 ; i<sv_maxclients->integer ; i++) {
		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if ( client->state < CS_CONNECTED) {
			continue;
		}

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse ) );
		if ( denied ) {
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, denied );
			Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i );
			continue;
		}

		if(client->state == CS_ACTIVE)
			SV_ClientEnterWorld(client, &client->lastUsercmd);
		else
		{
			// If we don't reset client->lastUsercmd and are restarting during map load,
			// the client will hang because we'll use the last Usercmd from the previous map,
			// which is wrong obviously.
			SV_ClientEnterWorld(client, NULL);
		}
	}	

	// run another frame to allow things to look at all the players
	VM_Call (gvm, GAME_RUN_FRAME, sv.time);
	sv.time += 100;
	svs.time += 100;
}
Beispiel #16
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f( void ) {
	int			i, j;
	client_t	*client;
	player_t	*player;
	char		*denied;
	qboolean	isBot;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId ) {
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	// let game delay or pervent the restart or force full map reload
	sv.restartTime = VM_Call( gvm, GAME_MAP_RESTART, sv.time, sv.restartTime );

	if( sv.restartTime > sv.time ) {
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified || sv.restartTime < 0 ) {
		char	mapname[MAX_QPATH];

		Com_Printf( "variable change -- restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );

		SV_SpawnServer( mapname, qfalse );
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid	
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );

	// if a map_restart occurs while a client is changing maps, we need
	// to give them the correct time so that when they finish loading
	// they don't violate the backwards time check in cl_cgame.c
	for (i=0 ; i<sv_maxclients->integer ; i++) {
		if (svs.clients[i].state == CS_PRIMED) {
			svs.clients[i].oldServerTime = sv.restartTime;
		}
	}

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for (i = 0; i < 3; i++)
	{
		VM_Call (gvm, GAME_RUN_FRAME, sv.time);
		sv.time += 100;
		svs.time += 100;
	}

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for (i=0 ; i<sv_maxclients->integer ; i++) {
		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if ( client->state < CS_CONNECTED) {
			continue;
		}

		if ( client->netchan.remoteAddress.type == NA_BOT ) {
			isBot = qtrue;
		} else {
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand( client, -1, "map_restart\n" );

		for ( j = 0; j < MAX_SPLITVIEW; j++ ) {
			player = client->localPlayers[j];

			if ( !player )
				continue;

			// setup entity before connecting
			SV_SetupPlayerEntity( player );

			// connect the client again, without the firstTime flag
			denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_PLAYER_CONNECT, player - svs.players, qfalse, isBot, client - svs.clients, j ) );
			player = client->localPlayers[j]; // may be NULL if game dropped player
			if ( denied ) {
				// this generally shouldn't happen, because the player
				// was connected before the level change
				if ( player != NULL ) {
					SV_DropPlayer( player, denied );
				}
				Com_Printf( "SV_MapRestart_f: dropped client %i - denied!\n", i );
				continue;
			}

			if(client->state == CS_ACTIVE)
				SV_PlayerEnterWorld( player, &player->lastUsercmd );
			else
			{
				// If we don't reset player->lastUsercmd and are restarting during map load,
				// the client will hang because we'll use the last Usercmd from the previous map,
				// which is wrong obviously.
				SV_PlayerEnterWorld( player, NULL );
			}
		}
	}

	// run another frame to allow things to look at all the players
	VM_Call (gvm, GAME_RUN_FRAME, sv.time);
	sv.time += 100;
	svs.time += 100;
}
Beispiel #17
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f(void)
{
	int         i;
	client_t    *client;
	char        *denied;
	qboolean    isBot;
	int         delay = 0;
	gamestate_t new_gs, old_gs;

	// make sure we aren't restarting twice in the same frame
	if (com_frameTime == sv.serverId)
	{
		return;
	}

	// make sure server is running
	if (!com_sv_running->integer)
	{
		Com_Printf("Server is not running.\n");
		return;
	}

	if (Cmd_Argc() > 1)
	{
		delay = atoi(Cmd_Argv(1));
	}

	if (delay)
	{
		sv.restartTime = svs.time + delay * 1000;
		SV_SetConfigstring(CS_WARMUP, va("%i", sv.restartTime));
		return;
	}

	// read in gamestate or just default to GS_PLAYING
	old_gs = atoi(Cvar_VariableString("gamestate"));

	if (Cmd_Argc() > 2)
	{
		new_gs = atoi(Cmd_Argv(2));
	}
	else
	{
		new_gs = GS_PLAYING;
	}

	if (!SV_TransitionGameState(new_gs, old_gs, delay))
	{
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if (sv_maxclients->modified)
	{
		char mapname[MAX_QPATH];

		Com_Printf("sv_maxclients variable change -- restarting.\n");
		// restart the map the slow way
		Q_strncpyz(mapname, Cvar_VariableString("mapname"), sizeof(mapname));

		SV_SpawnServer(mapname);
		return;
	}

	SV_DemoStopAll();

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set("sv_serverid", va("%i", sv.serverId));

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state      = SS_LOADING;
	sv.restarting = qtrue;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for (i = 0; i < GAME_INIT_FRAMES; i++)
	{
		VM_Call(gvm, GAME_RUN_FRAME, svs.time);
		svs.time += FRAMETIME;
	}

	sv.state      = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for (i = 0 ; i < sv_maxclients->integer ; i++)
	{
		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if (client->state < CS_CONNECTED)
		{
			continue;
		}

		if (client->netchan.remoteAddress.type == NA_BOT)
		{
			isBot = qtrue;
		}
		else
		{
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand(client, "map_restart\n");

		// connect the client again, without the firstTime flag
		denied = VM_ExplicitArgPtr(gvm, VM_Call(gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot));
		if (denied)
		{
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient(client, denied);
			if (!isBot)
			{
				Com_Printf("SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i);   // bk010125
			}

			continue;
		}

		// Player won't enter the world until the download is done
		if (client->download == 0)
		{
			if (client->state == CS_ACTIVE)
			{
				SV_ClientEnterWorld(client, &client->lastUsercmd);
			}
			else
			{
				// If we don't reset client->lastUsercmd and are restarting during map load,
				// the client will hang because we'll use the last Usercmd from the previous map,
				// which is wrong obviously.
				SV_ClientEnterWorld(client, NULL);
			}
		}
	}

	// run another frame to allow things to look at all the players
	VM_Call(gvm, GAME_RUN_FRAME, svs.time);
	svs.time += FRAMETIME;

	// start recording a demo
	if (sv_autoDemo->integer)
	{
		SV_DemoAutoDemoRecord();
	}
}