/*
=================
SV_Netchan_TransmitNextFragment
=================
*/
void SV_Netchan_TransmitNextFragment( client_t *client ) {
	Netchan_TransmitNextFragment( &client->netchan );
	while ( !client->netchan.unsentFragments && client->netchan_start_queue )
	{
		// make sure the netchan queue has been properly initialized (you never know)
		//%	if (!client->netchan_end_queue) {
		//%		Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n");
		//%	}
		// the last fragment was transmitted, check wether we have queued messages
		netchan_buffer_t* netbuf = client->netchan_start_queue;

		// pop from queue
		client->netchan_start_queue = netbuf->next;
		if ( !client->netchan_start_queue ) {
			client->netchan_end_queue = NULL;
		}

		if ( !SV_GameIsSinglePlayer() ) {
			SV_Netchan_Encode( client, &netbuf->msg, netbuf->lastClientCommandString );
		}
		Netchan_Transmit( &client->netchan, netbuf->msg.cursize, netbuf->msg.data );

		Z_Free( netbuf );
	}
}
Example #2
0
/*
================
SV_TransitionGameState

NERVE - SMF
================
*/
static qboolean SV_TransitionGameState(gamestate_t new_gs, gamestate_t old_gs, int delay)
{
	if (!SV_GameIsSinglePlayer() && !SV_GameIsCoop())
	{
		// we always do a warmup before starting match
		if (old_gs == GS_INTERMISSION && new_gs == GS_PLAYING)
		{
			new_gs = GS_WARMUP;
		}
	}

	// check if its a valid state transition
	if (!SV_CheckTransitionGameState(new_gs, old_gs))
	{
		return qfalse;
	}

	if (new_gs == GS_RESET)
	{
		new_gs = GS_WARMUP;
	}

	Cvar_Set("gamestate", va("%i", new_gs));

	return qtrue;
}
Example #3
0
/*
================
CL_Netchan_Transmit
================
*/
void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) {

#if defined RTCW_SP
//	int i;
	MSG_WriteByte( msg, clc_EOF );
//	for(i=CL_ENCODE_START;i<msg->cursize;i++) {
//		chksum[i-CL_ENCODE_START] = msg->data[i];
//	}

//	Huff_Compress( msg, CL_ENCODE_START );
#if DO_NET_ENCODE
	CL_Netchan_Encode( msg );
#endif
	Netchan_Transmit( chan, msg->cursize, msg->data );
#elif defined RTCW_MP
	MSG_WriteByte( msg, clc_EOF );
	CL_Netchan_Encode( msg );
	Netchan_Transmit( chan, msg->cursize, msg->data );
#else
	MSG_WriteByte( msg, clc_EOF );
	CL_WriteBinaryMessage( msg );

	if ( !SV_GameIsSinglePlayer() ) {
		CL_Netchan_Encode( msg );
	}
	Netchan_Transmit( chan, msg->cursize, msg->data );
#endif // RTCW_XX

}
Example #4
0
/*
===============
SV_BoundMaxClients

===============
*/
void SV_BoundMaxClients( int minimum )
{
	// get the current maxclients value
#ifdef __MACOS__
	Cvar_Get( "sv_maxclients", "16", 0 );  //DAJ HOG
#else
	Cvar_Get( "sv_maxclients", "20", 0 );  // NERVE - SMF - changed to 20 from 8
#endif

	// START    xkan, 10/03/2002
	// allow many bots in single player. note that this pretty much means all previous
	// settings will be ignored (including the one set through "seta sv_maxclients <num>"
	// in user profile's wolfconfig_mp.cfg). also that if the user subsequently start
	// the server in multiplayer mode, the number of clients will still be the number
	// set here, which may be wrong - we can certainly just set it to a sensible number
	// when it is not in single player mode in the else part of the if statement when
	// necessary
	if ( SV_GameIsSinglePlayer() || SV_GameIsCoop() )
	{
		Cvar_Set( "sv_maxclients", "64" );
	}

	// END      xkan, 10/03/2002

	sv_maxclients->modified = qfalse;

	if ( sv_maxclients->integer < minimum )
	{
		Cvar_Set( "sv_maxclients", va( "%i", minimum ) );
	}
	else if ( sv_maxclients->integer > MAX_CLIENTS )
	{
		Cvar_Set( "sv_maxclients", va( "%i", MAX_CLIENTS ) );
	}
}
/*
================
CL_Netchan_Transmit
================
*/
void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) {
	MSG_WriteByte( msg, clc_EOF );
	CL_WriteBinaryMessage( msg );

	if ( !SV_GameIsSinglePlayer() ) {
		CL_Netchan_Encode( msg );
	}
	Netchan_Transmit( chan, msg->cursize, msg->data );
}
Example #6
0
void SV_MasterHeartbeat( const char *hbname ) {
	static netadr_t adr[MAX_MASTER_SERVERS];
	int i;

	if ( SV_GameIsSinglePlayer() ) {
		return;     // no heartbeats for SP
	}

	// "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 = BigShort( 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],
						BigShort( 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
		NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", hbname );
	}
}
Example #7
0
/*
=================
SVC_GameCompleteStatus

NERVE - SMF - Send serverinfo cvars, etc to master servers when
game complete. Useful for tracking global player stats.
=================
*/
void SVC_GameCompleteStatus( netadr_t from ) {
	char player[1024];
	char status[MAX_MSGLEN];
	int i;
	client_t    *cl;
	playerState_t   *ps;
	int statusLength;
	int playerLength;
	char infostring[MAX_INFO_STRING];

	// ignore if we are in single player
	if ( SV_GameIsSinglePlayer() ) {
		return;
	}

	//bani - bugtraq 12534
	if ( !SV_VerifyChallenge( Cmd_Argv( 1 ) ) ) {
		return;
	}

	strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO | CVAR_SERVERINFO_NOUPDATE ) );

	// echo back the parameter to status. so master servers can use it as a challenge
	// to prevent timed spoofed reply packets that add ghost servers
	Info_SetValueForKey( infostring, "challenge", Cmd_Argv( 1 ) );

	// add "demo" to the sv_keywords if restricted
	if ( Cvar_VariableValue( "fs_restrict" ) ) {
		char keywords[MAX_INFO_STRING];

		Com_sprintf( keywords, sizeof( keywords ), "ettest %s",
					 Info_ValueForKey( infostring, "sv_keywords" ) );
		Info_SetValueForKey( infostring, "sv_keywords", keywords );
	}

	status[0] = 0;
	statusLength = 0;

	for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
		cl = &svs.clients[i];
		if ( cl->state >= CS_CONNECTED ) {
			ps = SV_GameClientNum( i );
			Com_sprintf( player, sizeof( player ), "%i %i \"%s\"\n",
						 ps->persistant[PERS_SCORE], cl->ping, cl->name );
			playerLength = strlen( player );
			if ( statusLength + playerLength >= sizeof( status ) ) {
				break;      // can't hold any more
			}
			strcpy( status + statusLength, player );
			statusLength += playerLength;
		}
	}

	NET_OutOfBandPrint( NS_SERVER, from, "gameCompleteStatus\n%s\n%s", infostring, status );
}
Example #8
0
/*
===============
SV_BotLibSetup
===============
*/
int SV_BotLibSetup(void)
{
	static cvar_t  *bot_norcd;
	static cvar_t  *bot_frameroutingupdates;

#ifdef PRE_RELEASE_DEMO
	return 0;
#endif

	if(!bot_enable)
	{
		return 0;
	}

	if(!botlib_export)
	{
		Com_Printf(S_COLOR_RED "Error: SV_BotLibSetup without SV_BotInitBotLib\n");
		return -1;
	}

#if defined(USE_BOTLIB)
	// RF, set RCD calculation status
	bot_norcd = Cvar_Get("bot_norcd", "0", 0);
	botlib_export->BotLibVarSet("bot_norcd", bot_norcd->string);

	// RF, set AAS routing max per frame
	if(SV_GameIsSinglePlayer())
	{
		bot_frameroutingupdates = Cvar_Get("bot_frameroutingupdates", "9999999", 0);
	}
	else
	{							// more restrictive in multiplayer
		bot_frameroutingupdates = Cvar_Get("bot_frameroutingupdates", "1000", 0);
	}
	botlib_export->BotLibVarSet("bot_frameroutingupdates", bot_frameroutingupdates->string);

// START    Arnout changes, 28-08-2002.
// added single player
	return botlib_export->BotLibSetup((SV_GameIsSinglePlayer() || SV_GameIsCoop()));
// END  Arnout changes, 28-08-2002.
#endif
}
/*
=================
Netchan_SV_Process
=================
*/
qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) {
	int ret;
	ret = Netchan_Process( &client->netchan, msg );
	if ( !ret ) {
		return qfalse;
	}
	if ( !SV_GameIsSinglePlayer() ) {
		SV_Netchan_Decode( client, msg );
	}
	return qtrue;
}
/*
=================
CL_Netchan_Process
=================
*/
qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg ) {
	int ret;

	ret = Netchan_Process( chan, msg );
	if ( !ret ) {
		return qfalse;
	}
	if ( !SV_GameIsSinglePlayer() ) {
		CL_Netchan_Decode( msg );
	}
	newsize += msg->cursize;
	return qtrue;
}
Example #11
0
/*
=================
SV_MasterGameCompleteStatus

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

	if ( SV_GameIsSinglePlayer() ) {
		return;     // no master game status for SP
	}

	// "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 = BigShort( 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],
						BigShort( 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] );
	}
}
Example #12
0
/*
=================
CL_Netchan_Process
=================
*/
qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg ) {
	int ret;

#if defined RTCW_SP
//	int i;
//	static		int newsize = 0;
#endif // RTCW_XX

	ret = Netchan_Process( chan, msg );
	if ( !ret ) {
		return qfalse;
	}

#if (defined RTCW_SP && DO_NET_ENCODE) || defined RTCW_MP
	CL_Netchan_Decode( msg );
#elif defined RTCW_ET
	if ( !SV_GameIsSinglePlayer() ) {
		CL_Netchan_Decode( msg );
	}
#endif

#if defined RTCW_SP
//	Huff_Decompress( msg, CL_DECODE_START );
//	for(i=CL_DECODE_START+msg->readcount;i<msg->cursize;i++) {
//		if (msg->data[i] != chksum[i-(CL_DECODE_START+msg->readcount)]) {
//			Com_Error(ERR_DROP,"bad %d v %d\n", msg->data[i], chksum[i-(CL_DECODE_START+msg->readcount)]);
//		}
//	}
#endif // RTCW_XX

	newsize += msg->cursize;

#if defined RTCW_SP
//	Com_Printf("saved %d to %d (%d%%)\n", (oldsize>>3), newsize, 100-(newsize*100/(oldsize>>3)));
#endif // RTCW_XX

	return qtrue;
}
/*
===============
SV_Netchan_Transmit

TTimo
show_bug.cgi?id=462
if there are some unsent fragments (which may happen if the snapshots
and the gamestate are fragmenting, and collide on send for instance)
then buffer them and make sure they get sent in correct order
================
*/
void SV_Netchan_Transmit( client_t *client, msg_t *msg ) {   //int length, const byte *data ) {
	MSG_WriteByte( msg, svc_EOF );
	SV_WriteBinaryMessage( msg, client );

	if ( client->netchan.unsentFragments ) {
		netchan_buffer_t *netbuf;
		//Com_DPrintf("SV_Netchan_Transmit: there are unsent fragments remaining\n");
		netbuf = (netchan_buffer_t *)Z_Malloc( sizeof( netchan_buffer_t ) );

		// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
		MSG_Copy( &netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg );

		// copy the command, since the command number used for encryption is
		// already compressed in the buffer, and receiving a new command would
		// otherwise lose the proper encryption key
		strcpy( netbuf->lastClientCommandString, client->lastClientCommandString );

		// insert it in the queue, the message will be encoded and sent later
		//%	*client->netchan_end_queue = netbuf;
		//%	client->netchan_end_queue = &(*client->netchan_end_queue)->next;
		netbuf->next = NULL;
		if ( !client->netchan_start_queue ) {
			client->netchan_start_queue = netbuf;
		} else {
			client->netchan_end_queue->next = netbuf;
		}
		client->netchan_end_queue = netbuf;

		// emit the next fragment of the current message for now
		Netchan_TransmitNextFragment( &client->netchan );
	} else {
		if ( !SV_GameIsSinglePlayer() ) {
			SV_Netchan_Encode( client, msg, client->lastClientCommandString );
		}
		Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
	}
}
Example #14
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
}
Example #15
0
/*
===============
SV_MasterHeartbeat
===============
*/
void SV_MasterHeartbeat( const char *hbname ) {
	static netadr_t adr[MAX_MASTER_SERVERS][2];
	int				i, res, netenabled;

	// Update Server doesn't send heartbeat
#if defined (UPDATE_SERVER)
	return;
#endif

	netenabled = Cvar_VariableIntegerValue("net_enabled");
	
	if ( SV_GameIsSinglePlayer() ) {
		return;     // no heartbeats for SP
	}

	// "dedicated 1" is for lan play, "dedicated 2" is for inet public play
	if (!com_dedicated || com_dedicated->integer != 2 || !(netenabled & (NET_ENABLEV4 | NET_ENABLEV6))) {
		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 || (adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD)) {
			sv_master[i]->modified = false;

			if(netenabled & NET_ENABLEV4) {
				Com_Printf("Resolving %s (IPv4)\n", sv_master[i]->string);
				res = NET_StringToAdr(sv_master[i]->string, &adr[i][0], NA_IP);

				if(res == 2) {
					// if no port was specified, use the default master port
					adr[i][0].port = BigShort(PORT_MASTER);
				}
			
				if(res) {
					Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][0]));
				} else {
					Com_Printf( "%s has no IPv4 address.\n", sv_master[i]->string);
				}
			}
			
			if(netenabled & NET_ENABLEV6) {
				Com_Printf("Resolving %s (IPv6)\n", sv_master[i]->string);
				res = NET_StringToAdr(sv_master[i]->string, &adr[i][1], NA_IP6);

				if(res == 2) {
					// if no port was specified, use the default master port
					adr[i][1].port = BigShort(PORT_MASTER);
				}
				
				if(res) {
					Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][1]));
				} else {
					Com_Printf( "%s has no IPv6 address.\n", sv_master[i]->string);
				}
			}

			if(adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD) {
				// 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 = false;
				continue;
			}
		}

		Com_Printf( "Sending heartbeat to the official OpenWolf servers list %s\n", sv_master[i]->string );

		// this command should be changed if the server info / status format
		// ever incompatably changes

		if(adr[i][0].type != NA_BAD) {
			NET_OutOfBandPrint( NS_SERVER, adr[i][0], "heartbeat %s\n", HEARTBEAT_GAME );
		}
		if(adr[i][1].type != NA_BAD) {
			NET_OutOfBandPrint( NS_SERVER, adr[i][1], "heartbeat %s\n", HEARTBEAT_GAME );
		}
	}

#if defined (USE_PHP)
	// Send to the main master.
	if (svs.queryDone) {
		pthread_exit(&svs.thQuery);
		svs.queryDone = 0;
	} else {
		SV_PHPMaster();
	}
#endif
}
Example #16
0
/*
================
SVC_Info

Responds with a short info message that should be enough to determine
if a user is interested in a server to do a full status
================
*/
void SVC_Info(netadr_t from) {
	int             i, count;
	char           *gamedir, infostring[MAX_INFO_STRING], *antilag, *weaprestrict, *balancedteams;

	// ignore if we are in single player
	if(SV_GameIsSinglePlayer()) {
		return;
	}

	//bani - bugtraq 12534
	if(!SV_VerifyChallenge(Cmd_Argv(1))) {
		return;
	}

	/*
	 * Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led
	 * to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory.
	*/
	// A maximum challenge length of 128 should be more than plenty.
	if(strlen(Cmd_Argv(1)) > 128) {
		return;
	}

#if defined (UPDATE_SERVER)
	return;
#endif

	// don't count privateclients
	count = 0;
	for(i = sv_privateClients->integer; i < sv_maxclients->integer; i++) {
		if(svs.clients[i].state >= CS_CONNECTED) {
			count++;
		}
	}

	infostring[0] = 0;

	// echo back the parameter to status. so servers can use it as a challenge
	// to prevent timed spoofed reply packets that add ghost servers
	Info_SetValueForKey(infostring, "challenge", Cmd_Argv(1));
	Info_SetValueForKey(infostring, "protocol", va("%i", com_protocol->integer));
	Info_SetValueForKey(infostring, "hostname", sv_hostname->string);
	Info_SetValueForKey(infostring, "serverload", va("%i", svs.serverLoad));
	Info_SetValueForKey(infostring, "mapname", sv_mapname->string);
	Info_SetValueForKey(infostring, "clients", va("%i", count));
	Info_SetValueForKey(infostring, "sv_maxclients", va("%i", sv_maxclients->integer - sv_privateClients->integer));
	//Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) );
	Info_SetValueForKey(infostring, "gametype", Cvar_VariableString("g_gametype"));
	Info_SetValueForKey(infostring, "pure", va("%i", sv_pure->integer));

#ifdef USE_VOIP
	if (sv_voip->integer) {
		Info_SetValueForKey( infostring, "voip", va("%i", sv_voip->integer ) );
	}
#endif	
	
	if(sv_minPing->integer) {
		Info_SetValueForKey(infostring, "minPing", va("%i", sv_minPing->integer));
	}
	if(sv_maxPing->integer) {
		Info_SetValueForKey(infostring, "maxPing", va("%i", sv_maxPing->integer));
	}
	gamedir = Cvar_VariableString("fs_game");
	if(*gamedir) {
		Info_SetValueForKey(infostring, "game", gamedir);
	}
	Info_SetValueForKey(infostring, "sv_allowAnonymous", va("%i", sv_allowAnonymous->integer));

	// Rafael gameskill
//  Info_SetValueForKey (infostring, "gameskill", va ("%i", sv_gameskill->integer));
	// done

	Info_SetValueForKey(infostring, "friendlyFire", va("%i", sv_friendlyFire->integer));	// NERVE - SMF
	Info_SetValueForKey(infostring, "maxlives", va("%i", sv_maxlives->integer ? 1 : 0));	// NERVE - SMF
	Info_SetValueForKey(infostring, "needpass", va("%i", sv_needpass->integer ? 1 : 0));
	Info_SetValueForKey(infostring, "gamename", GAMENAME_STRING);	// Arnout: to be able to filter out Quake servers

	// TTimo
	antilag = Cvar_VariableString("g_antilag");
	if(antilag) {
		Info_SetValueForKey(infostring, "g_antilag", antilag);
	}

	weaprestrict = Cvar_VariableString("g_heavyWeaponRestriction");
	if(weaprestrict) {
		Info_SetValueForKey(infostring, "weaprestrict", weaprestrict);
	}

	balancedteams = Cvar_VariableString("g_balancedteams");
	if(balancedteams) {
		Info_SetValueForKey(infostring, "balancedteams", balancedteams);
	}

	NET_OutOfBandPrint(NS_SERVER, from, "infoResponse\n%s", infostring);
}
Example #17
0
/*
================
SVC_Info

Responds with a short info message that should be enough to determine
if a user is interested in a server to do a full status
================
*/
void SVC_Info( netadr_t from ) {
	int i, count;
	const char    *gamedir;
	char infostring[MAX_INFO_STRING];

#if defined RTCW_MP
	const char    *antilag;

	// DHM - Nerve
#ifdef UPDATE_SERVER
	return;
#endif
#endif // RTCW_XX

#if defined RTCW_ET
	const char    *antilag;
	const char    *weaprestrict;
	const char    *balancedteams;

	// ignore if we are in single player
	if ( SV_GameIsSinglePlayer() ) {
		return;
	}
#endif // RTCW_XX

#if !defined RTCW_ET
	// ignore if we are in single player
	if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) {
		return;
	}
#endif // RTCW_XX

#if defined RTCW_ET
	//bani - bugtraq 12534
	if ( !SV_VerifyChallenge( Cmd_Argv( 1 ) ) ) {
		return;
	}
#endif // RTCW_XX

	// don't count privateclients
	count = 0;
	for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) {
		if ( svs.clients[i].state >= CS_CONNECTED ) {
			count++;
		}
	}

	infostring[0] = 0;

	// echo back the parameter to status. so servers can use it as a challenge
	// to prevent timed spoofed reply packets that add ghost servers
	Info_SetValueForKey( infostring, "challenge", Cmd_Argv( 1 ) );

	Info_SetValueForKey( infostring, "protocol", va( "%i", PROTOCOL_VERSION ) );
	Info_SetValueForKey( infostring, "hostname", sv_hostname->string );

#if defined RTCW_ET
	Info_SetValueForKey( infostring, "serverload", va( "%i", svs.serverLoad ) );
#endif // RTCW_XX

	Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
	Info_SetValueForKey( infostring, "clients", va( "%i", count ) );
	Info_SetValueForKey( infostring, "sv_maxclients",
						 va( "%i", sv_maxclients->integer - sv_privateClients->integer ) );

#if !defined RTCW_ET
	Info_SetValueForKey( infostring, "gametype", va( "%i", sv_gametype->integer ) );
#else
	Info_SetValueForKey( infostring, "gametype", Cvar_VariableString( "g_gametype" ) );
#endif // RTCW_XX

	Info_SetValueForKey( infostring, "pure", va( "%i", sv_pure->integer ) );

	if ( sv_minPing->integer ) {
		Info_SetValueForKey( infostring, "minPing", va( "%i", sv_minPing->integer ) );
	}
	if ( sv_maxPing->integer ) {
		Info_SetValueForKey( infostring, "maxPing", va( "%i", sv_maxPing->integer ) );
	}
	gamedir = Cvar_VariableString( "fs_game" );
	if ( *gamedir ) {
		Info_SetValueForKey( infostring, "game", gamedir );
	}
	Info_SetValueForKey( infostring, "sv_allowAnonymous", va( "%i", sv_allowAnonymous->integer ) );

	// Rafael gameskill

#if !defined RTCW_ET
	Info_SetValueForKey( infostring, "gameskill", va( "%i", sv_gameskill->integer ) );
#else
//	Info_SetValueForKey (infostring, "gameskill", va ("%i", sv_gameskill->integer));
#endif // RTCW_XX

	// done

#if !defined RTCW_SP
	Info_SetValueForKey( infostring, "friendlyFire", va( "%i", sv_friendlyFire->integer ) );        // NERVE - SMF
	Info_SetValueForKey( infostring, "maxlives", va( "%i", sv_maxlives->integer ? 1 : 0 ) );        // NERVE - SMF

#if !defined RTCW_ET
	Info_SetValueForKey( infostring, "tourney", va( "%i", sv_tourney->integer ) );              // NERVE - SMF
#endif // RTCW_XX

#if defined RTCW_ET
	Info_SetValueForKey( infostring, "needpass", va( "%i", sv_needpass->integer ? 1 : 0 ) );
#endif // RTCW_XX

	Info_SetValueForKey( infostring, "gamename", GAMENAME_STRING );                               // Arnout: to be able to filter out Quake servers

	// TTimo
	antilag = Cvar_VariableString( "g_antilag" );
	if ( antilag ) {
		Info_SetValueForKey( infostring, "g_antilag", antilag );
	}
#endif // RTCW_XX

#if defined RTCW_ET
	weaprestrict = Cvar_VariableString( "g_heavyWeaponRestriction" );
	if ( weaprestrict ) {
		Info_SetValueForKey( infostring, "weaprestrict", weaprestrict );
	}

	balancedteams = Cvar_VariableString( "g_balancedteams" );
	if ( balancedteams ) {
		Info_SetValueForKey( infostring, "balancedteams", balancedteams );
	}
#endif // RTCW_XX

	NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
}
Example #18
0
void SV_UpdateConfigStrings( void )
{
	int      len, i, index;
	client_t *client;
	int      maxChunkSize = MAX_STRING_CHARS - 24;

	for ( index = 0; index < MAX_CONFIGSTRINGS; index++ )
	{
		if ( !sv.configstringsmodified[ index ] )
		{
			continue;
		}

		sv.configstringsmodified[ index ] = qfalse;

		// send it to all the clients if we aren't
		// spawning a new server
		if ( sv.state == SS_GAME || sv.restarting )
		{
			// send the data to all relevent clients
			for ( i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++ )
			{
				if ( client->state < CS_PRIMED )
				{
					continue;
				}

				// do not always send server info to all clients
				if ( index == CS_SERVERINFO && client->gentity && ( client->gentity->r.svFlags & SVF_NOSERVERINFO ) )
				{
					continue;
				}

				// RF, don't send to bot/AI
				// Gordon: Note: might want to re-enable later for bot support
				// RF, re-enabled
				// Arnout: removed hardcoded gametype
				// Arnout: added coop
				if ( ( SV_GameIsSinglePlayer() || SV_GameIsCoop() ) && client->gentity && ( client->gentity->r.svFlags & SVF_BOT ) )
				{
					continue;
				}

				len = strlen( sv.configstrings[ index ] );

				if ( len >= maxChunkSize )
				{
					int  sent = 0;
					int  remaining = len;
					char *cmd;
					char buf[ MAX_STRING_CHARS ];

					while ( remaining > 0 )
					{
						if ( sent == 0 )
						{
							cmd = "bcs0";
						}
						else if ( remaining < maxChunkSize )
						{
							cmd = "bcs2";
						}
						else
						{
							cmd = "bcs1";
						}

						Q_strncpyz( buf, &sv.configstrings[ index ][ sent ], maxChunkSize );

						SV_SendServerCommand( client, "%s %i \"%s\"\n", cmd, index, buf );

						sent += ( maxChunkSize - 1 );
						remaining -= ( maxChunkSize - 1 );
					}
				}
				else
				{
					// standard cs, just send it
					SV_SendServerCommand( client, "cs %i \"%s\"\n", index, sv.configstrings[ index ] );
				}
			}
		}
	}
}
Example #19
0
/*
==================
SV_Map_f

Restart the server on a different map
==================
*/
static void SV_Map_f(void) {
	char           *cmd, *map, smapname[MAX_QPATH], mapname[MAX_QPATH], expanded[MAX_QPATH], *cl_profileStr = Cvar_VariableString("cl_profile");
	qboolean        killBots, cheat, buildScript;
	int             savegameTime = -1;

	map = Cmd_Argv(1);
	if(!map) {
		return;
	}

	if(!com_gameInfo.spEnabled) {
		if(!Q_stricmp(Cmd_Argv(0), "spdevmap") || !Q_stricmp(Cmd_Argv(0), "spmap")) {
			Com_Printf("Single Player is not enabled.\n");
			return;
		}
	}

	buildScript = (qboolean)Cvar_VariableIntegerValue("com_buildScript");

	if(SV_GameIsSinglePlayer()) {
		if(!buildScript && sv_reloading->integer && sv_reloading->integer != RELOAD_NEXTMAP) { // game is in 'reload' mode, don't allow starting new maps yet.
			return;
		}

		// Trap a savegame load
		if(strstr(map, ".sav")) {
			// open the savegame, read the mapname, and copy it to the map string
			char            savemap[MAX_QPATH], savedir[MAX_QPATH];
			byte           *buffer;
			int             size, csize;

			if(com_gameInfo.usesProfiles && cl_profileStr[0]) {
				Com_sprintf(savedir, sizeof(savedir), "profiles/%s/save/", cl_profileStr);
			} else {
				Q_strncpyz(savedir, "save/", sizeof(savedir));
			}

			if(!(strstr(map, savedir) == map)) {
				Com_sprintf(savemap, sizeof(savemap), "%s%s", savedir, map);
			} else {
				strcpy(savemap, map);
			}

			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);

			if(Q_stricmp(savemap, va("%scurrent.sav", savedir)) != 0)
			{
				// copy it to the current savegame file
				FS_WriteFile(va("%scurrent.sav", savedir), buffer, size);
				// make sure it is the correct size
				csize = FS_ReadFile(va("%scurrent.sav", savedir), NULL);
				if(csize != size) {
					Hunk_FreeTempMemory(buffer);
					FS_Delete(va("%scurrent.sav", savedir));
// TTimo
#ifdef __linux__
					Com_Error(ERR_DROP, "Unable to save game.\n\nPlease check that you have at least 5mb free of disk space in your home directory.");
#else
					Com_Error(ERR_DROP, "Insufficient free disk space.\n\nPlease free at least 5mb of free space on game drive.");
#endif
					return;
				}
			}

			// set the cvar, so the game knows it needs to load the savegame once the clients have connected
			Cvar_Set("savegame_loading", "1");
			// set the filename
			Cvar_Set("savegame_filename", savemap);

			// the mapname is at the very start of the savegame file
			Q_strncpyz(savemap, (char *)(buffer + sizeof(int)), sizeof(savemap));	// skip the version
			Q_strncpyz(smapname, savemap, sizeof(smapname));
			map = smapname;

			savegameTime = *(int *)(buffer + sizeof(int) + MAX_QPATH);

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

			Hunk_FreeTempMemory(buffer);
		} else {
			Cvar_Set("savegame_loading", "0");	// make sure it's turned off
												// set the filename
			Cvar_Set("savegame_filename", "");
		}
	} else {
		Cvar_Set("savegame_loading", "0");	// make sure it's turned off
											// set the filename
		Cvar_Set("savegame_filename", "");
	}

	// make sure the level exists before trying to change, so that
	// a typo at the server console won't end the game
	Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map);
	
	if(FS_ReadFile(expanded, NULL) == -1) {
		Com_Printf("Can't find map %s\n", expanded);
		return;
	}

	Cvar_Set("gamestate", va("%i", GS_INITIALIZE));	// NERVE - SMF - reset gamestate on map/devmap

	Cvar_Set("g_currentRound", "0");				// NERVE - SMF - reset the current round
	Cvar_Set("g_nextTimeLimit", "0");				// NERVE - SMF - reset the next time limit

	// START    Mad Doctor I changes, 8/14/2002.  Need a way to force load a single player map as single player
	if(!Q_stricmp(Cmd_Argv(0), "spdevmap") || !Q_stricmp(Cmd_Argv(0), "spmap")) {
		// This is explicitly asking for a single player load of this map
		Cvar_Set("g_gametype", va("%i", com_gameInfo.defaultSPGameType));
		// force latched values to get set
		Cvar_Get("g_gametype", va("%i", com_gameInfo.defaultSPGameType), CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, "test");
		// enable bot support for AI
		Cvar_Set("bot_enable", "1");
	}

	// Rafael gameskill
//  Cvar_Get ("g_gameskill", "3", CVAR_SERVERINFO | CVAR_LATCH);
	// done

	cmd = Cmd_Argv(0);

	if(!Q_stricmp(cmd, "devmap")) {
		cheat = qtrue;
		killBots = qtrue;
	} else if(!Q_stricmp(Cmd_Argv(0), "spdevmap")) {
		cheat = qtrue;
		killBots = qtrue;
	} else {
		cheat = qfalse;
		killBots = qfalse;
	}

	// save the map name here cause on a map restart we reload the q3config.cfg
	// and thus nuke the arguments of the map command
	Q_strncpyz(mapname, map, sizeof(mapname));

	// start up the map
	SV_SpawnServer(mapname, killBots);

	// set the cheat value
	// if the level was started with "map <levelname>", then
	// cheats will not be allowed.  If started with "devmap <levelname>"
	// then cheats will be allowed
	if(cheat) {
		Cvar_Set("sv_cheats", "1");
	} else {
		Cvar_Set("sv_cheats", "0");
	}
}
Example #20
0
/*
================
SV_SpawnServer

Change the server to a new map, taking all connected
clients along with it.
This is NOT called for map_restart
================
*/
void SV_SpawnServer( char *server, qboolean killBots )
{
	int        i;
	int        checksum;
	qboolean   isBot;
	const char *p;

	// shut down the existing game if it is running
	SV_ShutdownGameProgs();

	Com_Printf( "------ Server Initialization ------\n" );
	Com_Printf( "Server: %s\n", server );

	// if not running a dedicated server CL_MapLoading will connect the client to the server
	// also print some status stuff
	CL_MapLoading();

	// make sure all the client stuff is unloaded
	CL_ShutdownAll();

	// clear the whole hunk because we're (re)loading the server
	Hunk_Clear();

	// clear collision map data     // (SA) NOTE: TODO: used in missionpack
	CM_ClearMap();

	// wipe the entire per-level structure
	SV_ClearServer();

	// MrE: main zone should be pretty much emtpy at this point
	// except for file system data and cached renderer data
	Z_LogHeap();

	// allocate empty config strings
	for ( i = 0; i < MAX_CONFIGSTRINGS; i++ )
	{
		sv.configstrings[ i ] = CopyString( "" );
		sv.configstringsmodified[ i ] = qfalse;
	}

	// init client structures and svs.numSnapshotEntities
	if ( !Cvar_VariableValue( "sv_running" ) )
	{
		SV_Startup();
	}
	else
	{
		// check for maxclients change
		if ( sv_maxclients->modified )
		{
			SV_ChangeMaxClients();
		}

#ifdef USE_HUB_SERVER

		// if sv_owHubHost was changed, resolve the address again
		if ( sv_owHubHost->modified )
		{
			sv_owHubHost->modified = qfalse;
			SV_ResolveowHubHost();
		}

#endif
	}

	// clear pak references
	FS_ClearPakReferences( 0 );

	// allocate the snapshot entities on the hunk
	svs.snapshotEntities = Hunk_Alloc( sizeof( entityState_t ) * svs.numSnapshotEntities, h_high );
	svs.nextSnapshotEntities = 0;

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

	// set nextmap to the same map, but it may be overriden
	// by the game startup or another console command
	Cvar_Set( "nextmap", "map_restart 0" );
//  Cvar_Set( "nextmap", va("map %s", server) );

	// Ridah
	// DHM - Nerve :: We want to use the completion bar in multiplayer as well
	// Arnout: just always use it
//  if( !SV_GameIsSinglePlayer() ) {
	SV_SetExpectedHunkUsage( va( "maps/%s.bsp", server ) );
//  } else {
	// just set it to a negative number,so the cgame knows not to draw the percent bar
//      Cvar_Set( "com_expectedhunkusage", "-1" );
//  }

	// make sure we are not paused
	Cvar_Set( "cl_paused", "0" );

#if !defined( DO_LIGHT_DEDICATED )
	// get a new checksum feed and restart the file system
	srand( Sys_Milliseconds() );
	sv.checksumFeed = ( ( ( int ) rand() << 16 ) ^ rand() ) ^ Sys_Milliseconds();

	// DO_LIGHT_DEDICATED
	// only comment out when you need a new pure checksum string and it's associated random feed
	//Com_DPrintf("SV_SpawnServer checksum feed: %p\n", sv.checksumFeed);

#else // DO_LIGHT_DEDICATED implementation below
	// we are not able to randomize the checksum feed since the feed is used as key for pure_checksum computations
	// files.c 1776 : pack->pure_checksum = Com_BlockChecksumKey( fs_headerLongs, 4 * fs_numHeaderLongs, LittleLong(fs_checksumFeed) );
	// we request a fake randomized feed, files.c knows the answer
	srand( Sys_Milliseconds() );
	sv.checksumFeed = FS_RandChecksumFeed();
#endif
	FS_Restart( sv.checksumFeed );

	CM_LoadMap( va( "maps/%s.bsp", server ), qfalse, &checksum );

	// set serverinfo visible name
	Cvar_Set( "mapname", server );

	Cvar_Set( "sv_mapChecksum", va( "%i", checksum ) );

	sv_newGameShlib = Cvar_Get( "sv_newGameShlib", "", CVAR_TEMP );

	// serverid should be different each time
	sv.serverId = com_frameTime;
	sv.restartedServerId = sv.serverId;
	sv.checksumFeedServerId = sv.serverId;
	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );

	// clear physics interaction links
	SV_ClearWorld();

	// media configstring setting should be done during
	// the loading stage, so connected clients don't have
	// to load during actual gameplay
	sv.state = SS_LOADING;

	Cvar_Set( "sv_serverRestarting", "1" );

	// load and spawn all other entities
	SV_InitGameProgs();

	// don't allow a map_restart if game is modified
	// Arnout: there isn't any check done against this, obsolete
//  sv_gametype->modified = qfalse;

	// 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 );
		SV_BotFrame( svs.time );
		svs.time += FRAMETIME;
	}

	// create a baseline for more efficient communications
	SV_CreateBaseline();

	for ( i = 0; i < sv_maxclients->integer; i++ )
	{
		// send the new gamestate to all connected clients
		if ( svs.clients[ i ].state >= CS_CONNECTED )
		{
			char *denied;

			if ( svs.clients[ i ].netchan.remoteAddress.type == NA_BOT )
			{
				if ( killBots || SV_GameIsSinglePlayer() || SV_GameIsCoop() )
				{
					SV_DropClient( &svs.clients[ i ], "" );
					continue;
				}

				isBot = qtrue;
			}
			else
			{
				isBot = qfalse;
			}

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

			if ( denied )
			{
				// this generally shouldn't happen, because the client
				// was connected before the level change
				SV_DropClient( &svs.clients[ i ], denied );
			}
			else
			{
				if ( !isBot )
				{
					// when we get the next packet from a connected client,
					// the new gamestate will be sent
					svs.clients[ i ].state = CS_CONNECTED;
				}
				else
				{
					client_t       *client;
					sharedEntity_t *ent;

					client = &svs.clients[ i ];
					client->state = CS_ACTIVE;
					ent = SV_GentityNum( i );
					ent->s.number = i;
					client->gentity = ent;

					client->deltaMessage = -1;
					client->nextSnapshotTime = svs.time; // generate a snapshot immediately

					VM_Call( gvm, GAME_CLIENT_BEGIN, i );
				}
			}
		}
	}

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

	if ( sv_pure->integer )
	{
		// the server sends these to the clients so they will only
		// load pk3s also loaded at the server
		p = FS_LoadedPakChecksums();
		Cvar_Set( "sv_paks", p );

		if ( strlen( p ) == 0 )
		{
			Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" );
		}

		p = FS_LoadedPakNames();
		Cvar_Set( "sv_pakNames", p );

		// if a dedicated pure server we need to touch the cgame because it could be in a
		// seperate pk3 file and the client will need to load the latest cgame.qvm
		if ( com_dedicated->integer )
		{
			SV_TouchCGame();
		}
	}
	else
	{
		Cvar_Set( "sv_paks", "" );
		Cvar_Set( "sv_pakNames", "" );
	}

	// the server sends these to the clients so they can figure
	// out which pk3s should be auto-downloaded
	// NOTE: we consider the referencedPaks as 'required for operation'

	// we want the server to reference the mp_bin pk3 that the client is expected to load from
	SV_TouchCGameDLL();

	p = FS_ReferencedPakChecksums();
	Cvar_Set( "sv_referencedPaks", p );
	p = FS_ReferencedPakNames();
	Cvar_Set( "sv_referencedPakNames", p );

	// save systeminfo and serverinfo strings
	cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
	SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) );

	SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO | CVAR_SERVERINFO_NOUPDATE ) );
	cvar_modifiedFlags &= ~CVAR_SERVERINFO;

	// any media configstring setting now should issue a warning
	// and any configstring changes should be reliably transmitted
	// to all clients
	sv.state = SS_GAME;

	// send a heartbeat now so the master will get up to date info
	SV_Heartbeat_f();

	Hunk_SetMark();

	SV_UpdateConfigStrings();

	Cvar_Set( "sv_serverRestarting", "0" );

	Com_Printf( "-----------------------------------\n" );
}
Example #21
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");
}