Пример #1
0
/*
* SV_SendClientMessages
*/
void SV_SendClientMessages( void )
{
	int i;
	client_t *client;

	// send a message to each connected client
	for( i = 0, client = svs.clients; i < sv_maxclients->integer; i++, client++ )
	{
		if( client->state == CS_FREE || client->state == CS_ZOMBIE )
			continue;

		if( client->edict && ( client->edict->r.svflags & SVF_FAKECLIENT ) )
		{
			client->lastSentFrameNum = sv.framenum;
			continue;
		}

		if( !client->tvclient ) {
			SV_UpdateActivity();
		}

		if( client->state == CS_SPAWNED )
		{
			if( !SV_SendClientDatagram( client ) )
			{
				Com_Printf( "Error sending message to %s: %s\n", client->name, NET_ErrorString() );
				if( client->reliable )
				{
					SV_DropClient( client, DROP_TYPE_GENERAL, "Error sending message: %s\n", NET_ErrorString() );
				}
			}
		}
		else
		{
			// send pending reliable commands, or send heartbeats for not timing out
			if( client->reliableSequence > client->reliableAcknowledge ||
				svs.realtime - client->lastPacketSentTime > 1000 )
			{
				SV_InitClientMessage( client, &tmpMessage, NULL, 0 );
				SV_AddReliableCommandsToMessage( client, &tmpMessage );
				if( !SV_SendMessageToClient( client, &tmpMessage ) )
				{
					Com_Printf( "Error sending message to %s: %s\n", client->name, NET_ErrorString() );
					if( client->reliable )
					{
						SV_DropClient( client, DROP_TYPE_GENERAL, "Error sending message: %s\n", NET_ErrorString() );
					}
				}
			}
		}
	}
}
Пример #2
0
/*
* SV_AutoUpdateFromWeb
*/
void SV_AutoUpdateFromWeb( qboolean checkOnly )
{
	static const char *autoUpdateBaseUrl = APP_UPDATE_URL APP_SERVER_UPDATE_DIRECTORY;
	char checksumString1[32], checksumString2[32];
	unsigned int checksum;
	qboolean success;
	int length, filenum;
	qbyte *data;
	const char *token, *ptr;
	char path[MAX_QPATH];
	int downloadCount = 0, downloadFailed = 0;
	char newVersionTag[MAX_QPATH];
	qboolean newVersion = qfalse;

	if( !dedicated->integer )
		return;

	assert( svs.mapcmd[0] );

	if( !checkOnly )
		SV_UpdateActivity();

	Com_Printf( "\n" );
	Com_Printf( "========== Starting Auto Update ===========\n" );

	Com_Printf( "Checking for updates\n" );

	// download the update file list
	success = SV_WebDownload( autoUpdateBaseUrl, APP_SERVER_UPDATE_FILE, qtrue, qtrue );

	// set as last updated today
	if( !checkOnly )
		Cvar_ForceSet( "sv_lastAutoUpdate", va( "%i", (int)Com_DaysSince1900() ) );

	if( !success ) // no update to do
		goto done;

	// read the file list
	if( ( length = FS_FOpenBaseFile( APP_SERVER_UPDATE_FILE, &filenum, FS_READ ) ) == -1 )
	{
		Com_Printf( "WARNING: Couldn't find %s\n", path );
		goto done;
	}

	if( !length )
	{
		FS_FCloseFile( filenum );
		goto done;
	}

	data = Mem_TempMalloc( length + 1 );
	FS_Read( data, length, filenum );
	FS_FCloseFile( filenum );
	FS_RemoveBaseFile( APP_SERVER_UPDATE_FILE );

	ptr = (const char *)data;

	// first token is always the current release version
	token = COM_ParseExt( &ptr, qtrue );
	if( !token[0] )
		goto cancel;

	// compare versions
	Q_strncpyz( newVersionTag, token, sizeof( newVersionTag ) );
	if( atof( newVersionTag ) > atof( va( "%4.3f", APP_VERSION ) ) )
		newVersion = qtrue;

	while( ptr )
	{
		// we got what should be a checksum
		token = COM_ParseExt( &ptr, qtrue );
		if( !token[0] )
			goto cancel;

		// copy checksum reported by server
		Q_strncpyz( checksumString1, token, sizeof( checksumString1 ) );

		// get filename
		token = COM_ParseExt( &ptr, qtrue );
		if( !token[0] )
			goto cancel;

		// filename should never begin with a slash
		if( token[0] == '/' )
			token++;

		Q_strncpyz( path, token, sizeof( path ) );

		// we got what should be a file path
		if( !COM_ValidateRelativeFilename( path ) )
		{
			Com_Printf( "WARNING: Invalid filename %s\n", path );
			continue;
		}

		checksum = FS_ChecksumBaseFile( path );
		Q_snprintfz( checksumString2, sizeof( checksumString2 ), "%u", checksum );

		// if same checksum no need to update
		if( !strcmp( checksumString1, checksumString2 ) )
			continue;

		// if it's a pack file and the file exists it can't be replaced, so skip
		if( FS_CheckPakExtension( path ) && checksum )
		{
			Com_Printf( "WARNING: Purity check failed for: %s\n", path );
			Com_Printf( "WARNING: This file has been locally modified. It is highly \n" );
			Com_Printf( "WARNING: recommended to restore the original file.\n" );
			Com_Printf( "WARNING: Reinstalling \""APPLICATION"\" might be convenient.\n" );
			continue;	
		}

		if( checkOnly )
		{
			Com_Printf( "File update available : %s\n", path );
			continue;
		}
		
		if( developer->integer )
			Com_Printf( "Downloading update of %s (checksum %s local checksum %s)\n", path, checksumString1, checksumString2 );
		else
			Com_Printf( "Updating %s\n", path );

		if( !SV_WebDownload( autoUpdateBaseUrl, path, qtrue, qtrue ) )
		{
			Com_Printf( "Failed to update %s\n", path );
			downloadFailed++;
		}

		downloadCount++;
	}

cancel:
	Mem_TempFree( data );
done:
	if( newVersion )
	{
		if( downloadCount )
		{
			if( downloadFailed )
				Com_Printf( "This version of "APPLICATION" was updated incompletely\n" );
			else
				Com_Printf( "This version of "APPLICATION" was updated successfully\n\n" );
		}

		Com_Printf( "****** Version %s of "APPLICATION" is available. ******\n", newVersionTag );
		Com_Printf( "****** Please download the new version at "APP_URL" ******\n" );
	}
	else if( downloadCount )
	{
		if( downloadFailed )
			Com_Printf( APPLICATION" was updated incompletely\n" );
		else
			Com_Printf( APPLICATION" was updated successfully\n" );
	}
	else if( !checkOnly )
	{
		if( downloadFailed )
			Com_Printf( "At least one file failed to update\n" );
		else
			Com_Printf( APPLICATION" is up to date\n" );
	}

	Com_Printf( "========== Auto Update Finished ===========\n" );
	Com_Printf( "\n" );

	// update the map list, which also does a filesystem rescan
	ML_Update();

	// if there are any new filesystem entries, restart
	if( FS_GetNotifications() & FS_NOTIFT_NEWPAKS )
	{
		if( sv.state != ss_dead )
		{
			// restart the current map, SV_Map also rescans the filesystem
			Com_Printf( "The server will now restart...\n\n" );

			// start the default map if current map isn't available
			Cbuf_ExecuteText( EXEC_APPEND, va( "map %s\n", svs.mapcmd[0] ? svs.mapcmd : sv_defaultmap->string ) );
		}
	}
}
Пример #3
0
/*
* SV_SpawnServer
* Change the server to a new map, taking all connected clients along with it.
*/
static void SV_SpawnServer( const char *server, qboolean devmap )
{
	unsigned checksum;
	int i;

	if( devmap )
		Cvar_ForceSet( "sv_cheats", "1" );
	Cvar_FixCheatVars();

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

	svs.spawncount++;   // any partially connected client will be restarted

	Com_SetServerState( ss_dead );

	// wipe the entire per-level structure
	memset( &sv, 0, sizeof( sv ) );
	SV_ResetClientFrameCounters();
	svs.realtime = 0;
	svs.gametime = 0;
	SV_UpdateActivity();

	Q_strncpyz( sv.mapname, server, sizeof( sv.mapname ) );

	SV_SetServerConfigStrings();

	sv.nextSnapTime = 1000;

	Q_snprintfz( sv.configstrings[CS_WORLDMODEL], sizeof( sv.configstrings[CS_WORLDMODEL] ), "maps/%s.bsp", server );
	CM_LoadMap( svs.cms, sv.configstrings[CS_WORLDMODEL], qfalse, &checksum );

	Q_snprintfz( sv.configstrings[CS_MAPCHECKSUM], sizeof( sv.configstrings[CS_MAPCHECKSUM] ), "%i", checksum );

	// reserve the first modelIndexes for inline models
	for( i = 1; i < CM_NumInlineModels( svs.cms ); i++ )
		Q_snprintfz( sv.configstrings[CS_MODELS + i], sizeof( sv.configstrings[CS_MODELS + i] ), "*%i", i );

	// set serverinfo variable
	Cvar_FullSet( "mapname", sv.mapname, CVAR_SERVERINFO | CVAR_READONLY, qtrue );

	//
	// spawn the rest of the entities on the map
	//

	// precache and static commands can be issued during
	// map initialization
	sv.state = ss_loading;
	Com_SetServerState( sv.state );

	// set purelist
	SV_ReloadPureList();

	// load and spawn all other entities
	ge->InitLevel( sv.mapname, CM_EntityString( svs.cms ), CM_EntityStringLen( svs.cms ), 0, svs.gametime, svs.realtime );

	// run two frames to allow everything to settle
	ge->RunFrame( svc.snapFrameTime, svs.gametime );
	ge->RunFrame( svc.snapFrameTime, svs.gametime );

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

	// all precaches are complete
	sv.state = ss_game;
	Com_SetServerState( sv.state );

	Com_Printf( "-------------------------------------\n" );
}
Пример #4
0
/*
* SV_ParseClientMessage
* The current message is parsed for the given client
*/
void SV_ParseClientMessage( client_t *client, msg_t *msg )
{
	int c;
	char *s;
	qboolean move_issued;
	unsigned int cmdNum;

	if( !msg )
		return;

	SV_UpdateActivity();

	// only allow one move command
	move_issued = qfalse;
	while( 1 )
	{
		if( msg->readcount > msg->cursize )
		{
			Com_Printf( "SV_ParseClientMessage: badread\n" );
			SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Bad message" );
			return;
		}

		c = MSG_ReadByte( msg );
		if( c == -1 )
			break;

		switch( c )
		{
		default:
			Com_Printf( "SV_ParseClientMessage: unknown command char\n" );
			SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Unknown command char" );
			return;

		case clc_nop:
			break;

		case clc_move:
			{
				if( move_issued )
					return; // someone is trying to cheat...

				move_issued = qtrue;
				SV_ParseMoveCommand( client, msg );
			}
			break;

		case clc_svcack:
			{
				if( client->reliable )
				{
					Com_Printf( "SV_ParseClientMessage: svack from reliable client\n" );
					SV_DropClient( client, DROP_TYPE_GENERAL, "Error: svack from reliable client" );
					return;
				}
				cmdNum = MSG_ReadLong( msg );
				if( cmdNum < client->reliableAcknowledge || cmdNum > client->reliableSent )
				{
					//SV_DropClient( client, DROP_TYPE_GENERAL, "Error: bad server command acknowledged" );
					return;
				}
				client->reliableAcknowledge = cmdNum;
			}
			break;

		case clc_clientcommand:
			if( !client->reliable )
			{
				cmdNum = MSG_ReadLong( msg );
				if( cmdNum <= client->clientCommandExecuted )
				{
					s = MSG_ReadString( msg ); // read but ignore
					continue;
				}
				client->clientCommandExecuted = cmdNum;
			}
			s = MSG_ReadString( msg );
			SV_ExecuteUserCommand( client, s );
			if( client->state == CS_ZOMBIE )
				return; // disconnect command
			break;

		case clc_extension:
			if( 1 )
			{
				int ext, len;

				ext = MSG_ReadByte( msg );		// extension id
				MSG_ReadByte( msg );			// version number
				len = MSG_ReadShort( msg );		// command length

				switch( ext )
				{
				default:
					// unsupported
					MSG_SkipData( msg, len );
					break;
				}
			}
			break;
		}
	}
}