Beispiel #1
0
static void SV_CheckStartMatch (void)
{
	client_t *cl;

	if (!sv->spawned || sv->started)
		return;

	if (sv_maxclients->integer > 1) {
		cl = NULL;
		while ((cl = SV_GetNextClient(cl)) != NULL) {
			/* all players must have their actors spawned */
			if (cl->state != cs_spawned)
				return;
		}
	} else if (SV_GetClient(0)->state != cs_spawned) {
		/* in single player mode we must have received the 'spawnsoldiers' */
		return;
	}

	sv->started = true;

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL)
		if (cl->state != cs_free)
			SV_ClientCommand(cl, "startmatch\n");
}
Beispiel #2
0
/*
===================
SV_ExecuteClientMessage

Parse a client packet
===================
*/
void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
	int			c;

	while( 1 ) {
		if ( msg->readcount > msg->cursize ) {
			SV_DropClient (cl, "had a badread");
			return;
		}	

		c = MSG_ReadByte( msg );
		if ( c == -1 ) {
			break;
		}
				
		switch( c ) {
		default:
			SV_DropClient( cl,"had an unknown command char" );
			return;
						
		case clc_nop:
			break;

		case clc_move:
			SV_UserMove( cl, msg );
			break;

		case clc_clientCommand:
			SV_ClientCommand( cl, msg );
			if (cl->state == CS_ZOMBIE) {
				return;	// disconnect command
			}
			break;
		}
	}
}
Beispiel #3
0
/**
 * @brief If all connected clients have set their ready flag the server will spawn the clients
 * and that change the client state.
 * @sa SV_Spawn_f
 */
static void SV_CheckSpawnSoldiers (void)
{
	client_t *cl;

	/* already started? */
	if (sv->spawned)
		return;

	if (sv_maxclients->integer > 1) {
		cl = NULL;
		while ((cl = SV_GetNextClient(cl)) != NULL) {
			/* all players must be connected and all of them must have set
			 * the ready flag */
			if (cl->state != cs_began || !cl->player->isReady)
				return;
		}
	} else if (SV_GetClient(0)->state != cs_began) {
		/* in single player mode we must have received the 'begin' */
		return;
	}

	sv->spawned = qtrue;

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL)
		if (cl->state != cs_free)
			SV_ClientCommand(cl, "spawnsoldiers\n");
}
Beispiel #4
0
/**
 * @brief If all connected clients have set their ready flag the server will spawn the clients
 * and that change the client state.
 * @sa SV_Spawn_f
 */
static void SV_CheckSpawnSoldiers (void)
{
    /* already started? */
    if (sv->spawned)
        return;

    client_t* cl = nullptr;
    while ((cl = SV_GetNextClient(cl)) != nullptr) {
        /* all players must be connected and all of them must have set
         * the ready flag */
        if (cl->state != cs_began || !cl->player->isReady())
            return;
    }

    sv->spawned = true;

    cl = nullptr;
    while ((cl = SV_GetNextClient(cl)) != nullptr)
        if (cl->state != cs_free)
            SV_ClientCommand(cl, CL_SPAWNSOLDIERS "\n");
}
Beispiel #5
0
/**
 * @brief If all connected clients have set their ready flag the server will spawn the clients
 * and that change the client state.
 * @sa SV_Spawn_f
 */
static void SV_CheckSpawnSoldiers (void)
{
	client_t *cl;

	/* already started? */
	if (sv->spawned)
		return;

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL) {
		/* all players must be connected and all of them must have set
		 * the ready flag */
		if (cl->state != cs_began || !cl->player->isReady)
			return;
	}

	sv->spawned = true;

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL)
		if (cl->state != cs_free)
			SV_ClientCommand(cl, "spawnsoldiers\n");
}
Beispiel #6
0
/**
 * @brief Sends the first message from the server to a connected client.
 * This will be sent on the initial connection and upon each server load.
 * Client reads via CL_ParseServerData in cl_parse.c
 * @sa CL_Reconnect_f
 * @sa CL_ConnectionlessPacket
 */
static void SV_New_f (client_t *cl)
{
	Com_DPrintf(DEBUG_SERVER, "New() from %s\n", cl->name);

	if (cl->state != cs_connected) {
		if (cl->state == cs_spawning) {
			/* client typed 'reconnect/new' while connecting. */
			Com_Printf("SV_New_f: client typed 'reconnect/new' while connecting\n");
			SV_ClientCommand(cl, "\ndisconnect\nreconnect\n");
			SV_DropClient(cl, "");
		} else
			Com_DPrintf(DEBUG_SERVER, "WARNING: Illegal 'new' from %s, client state %d. This shouldn't happen...\n", cl->name, cl->state);
		return;
	}

	/* client state to prevent multiple new from causing high cpu / overflows. */
	SV_SetClientState(cl, cs_spawning);

	/* serverdata needs to go over for all types of servers
	 * to make sure the protocol is right, and to set the gamedir */

	/* send the serverdata */
	{
		const int playernum = cl - SV_GetClient(0);
		struct dbuffer *msg = new_dbuffer();
		NET_WriteByte(msg, svc_serverdata);
		NET_WriteLong(msg, PROTOCOL_VERSION);

		NET_WriteShort(msg, playernum);

		/* send full levelname */
		NET_WriteString(msg, SV_GetConfigString(CS_NAME));

		NET_WriteMsg(cl->stream, msg);
	}

	/* game server */
	if (Com_ServerState() == ss_game) {
		int i;
		for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
			const char *configString;
			/* CS_TILES and CS_POSITIONS can stretch over multiple configstrings,
			 * so don't send the middle parts again. */
			if (i > CS_TILES && i < CS_POSITIONS)
				continue;
			if (i > CS_POSITIONS && i < CS_MODELS)
				continue;

			configString = SV_GetConfigString(i);
			if (configString[0] != '\0') {
				struct dbuffer *msg = new_dbuffer();
				Com_DPrintf(DEBUG_SERVER, "sending configstring %d: %s\n", i, configString);
				NET_WriteByte(msg, svc_configstring);
				NET_WriteShort(msg, i);
				NET_WriteString(msg, configString);
				/* enqueue and free msg */
				NET_WriteMsg(cl->stream, msg);
			}
		}
	}

	SV_ClientCommand(cl, "precache\n");
}
Beispiel #7
0
/*
===================
SV_ExecuteClientMessage

Parse a client packet
===================
*/
void SV_ExecuteClientMessage( client_t *cl, msg_t *msg )
{
	int c;
	int serverId;

	MSG_Bitstream( msg );

	serverId = MSG_ReadLong( msg );
	cl->messageAcknowledge = MSG_ReadLong( msg );

	if ( cl->messageAcknowledge < 0 )
	{
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
#ifndef NDEBUG
		SV_DropClient( cl, "DEBUG: illegible client message" );
#endif
		return;
	}

	cl->reliableAcknowledge = MSG_ReadLong( msg );

	// NOTE: when the client message is fux0red the acknowledgement numbers
	// can be out of range, this could cause the server to send thousands of server
	// commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
	if ( cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS )
	{
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
#ifndef NDEBUG
		SV_DropClient( cl, "DEBUG: illegible client message" );
#endif
		cl->reliableAcknowledge = cl->reliableSequence;
		return;
	}

	// if this is a usercmd from a previous gamestate,
	// ignore it or retransmit the current gamestate
	//
	// if the client was downloading, let it stay at whatever serverId and
	// gamestate it was at.  This allows it to keep downloading even when
	// the gamestate changes.  After the download is finished, we'll
	// notice and send it a new game state
	//
	// show_bug.cgi?id=536
	// don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to ""
	// but we still need to read the next message to move to next download or send gamestate
	// I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else
	if ( serverId != sv.serverId && !*cl->downloadName && !strstr( cl->lastClientCommandString, "nextdl" ) )
	{
		if ( serverId >= sv.restartedServerId && serverId < sv.serverId )
		{
			// TTimo - use a comparison here to catch multiple map_restart
			// they just haven't caught the map_restart yet
			Log::Debug( "%s^7: ignoring pre map_restart / outdated client message", cl->name );
			return;
		}

		// if we can tell that the client has dropped the last
		// gamestate we sent them, resend it
		if ( cl->messageAcknowledge > cl->gamestateMessageNum )
		{
			Log::Debug( "%s^7: dropped gamestate, resending", cl->name );
			SV_SendClientGameState( cl );
		}

		// read optional clientCommand strings
		do
		{
			c = MSG_ReadByte( msg );

			if ( c == clc_EOF )
			{
				break;
			}

			if ( c != clc_clientCommand )
			{
				break;
			}

			if ( !SV_ClientCommand( cl, msg, true ) )
			{
				return; // we couldn't execute it because of the flood protection
			}

			if ( cl->state == clientState_t::CS_ZOMBIE )
			{
				return; // disconnect command
			}
		}
		while ( 1 );

		return;
	}

	// read optional clientCommand strings
	do
	{
		c = MSG_ReadByte( msg );

		if ( c == clc_EOF )
		{
			break;
		}

		if ( c != clc_clientCommand )
		{
			break;
		}

		if ( !SV_ClientCommand( cl, msg, false ) )
		{
			return; // we couldn't execute it because of the flood protection
		}

		if ( cl->state == clientState_t::CS_ZOMBIE )
		{
			return; // disconnect command
		}
	}
	while ( 1 );

	// read the usercmd_t
	if ( c == clc_move )
	{
		SV_UserMove( cl, msg, true );
	}
	else if ( c == clc_moveNoDelta )
	{
		SV_UserMove( cl, msg, false );
	}
	else if ( c != clc_EOF )
	{
		Log::Warn( "bad command byte for client %i\n", ( int )( cl - svs.clients ) );
	}

	SV_ParseBinaryMessage( cl, msg );

//  if ( msg->readcount != msg->cursize ) {
//      Log::Notice( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
//  }
}
Beispiel #8
0
/*
===================
SV_ExecuteClientMessage

Parse a client packet
===================
*/
void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
	int			c;
	int			serverId;

	MSG_Bitstream(msg);

	serverId = MSG_ReadLong( msg );
	cl->messageAcknowledge = MSG_ReadLong( msg );

	if (cl->messageAcknowledge < 0) {
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
		//SV_DropClient( cl, "illegible client message" );
		return;
	}

	cl->reliableAcknowledge = MSG_ReadLong( msg );

	// NOTE: when the client message is fux0red the acknowledgement numbers
	// can be out of range, this could cause the server to send thousands of server
	// commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
	if (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) {
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
		//SV_DropClient( cl, "illegible client message" );
		cl->reliableAcknowledge = cl->reliableSequence;
		return;
	}
	// if this is a usercmd from a previous gamestate,
	// ignore it or retransmit the current gamestate
	// 
	// if the client was downloading, let it stay at whatever serverId and
	// gamestate it was at.  This allows it to keep downloading even when
	// the gamestate changes.  After the download is finished, we'll
	// notice and send it a new game state
	if ( serverId != sv.serverId && !*cl->downloadName ) {
		if ( serverId == sv.restartedServerId ) {
			// they just haven't caught the map_restart yet
			return;
		}
		// if we can tell that the client has dropped the last
		// gamestate we sent them, resend it
		if ( cl->messageAcknowledge > cl->gamestateMessageNum ) {
			Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name );
			SV_SendClientGameState( cl );
		}
		return;
	}

	// read optional clientCommand strings
	do {
		c = MSG_ReadByte( msg );
		if ( c == clc_EOF ) {
			break;
		}
		if ( c != clc_clientCommand ) {
			break;
		}
		if ( !SV_ClientCommand( cl, msg ) ) {
			return;	// we couldn't execute it because of the flood protection
		}
		if (cl->state == CS_ZOMBIE) {
			return;	// disconnect command
		}
	} while ( 1 );

	// read the usercmd_t
	if ( c == clc_move ) {
		SV_UserMove( cl, msg, qtrue );
	} else if ( c == clc_moveNoDelta ) {
		SV_UserMove( cl, msg, qfalse );
	} else if ( c != clc_EOF ) {
		Com_Printf( "WARNING: bad command byte for client %i\n", cl - svs.clients );
	}
//	if ( msg->readcount != msg->cursize ) {
//		Com_Printf( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
//	}
}
Beispiel #9
0
/*
===================
SV_ExecuteClientMessage

Parse a client packet
===================
*/
void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
	int			c;
	int			serverId;

	MSG_Bitstream(msg);

	serverId = MSG_ReadLong( msg );
	cl->messageAcknowledge = MSG_ReadLong( msg );

	if (cl->messageAcknowledge < 0) {
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
#ifndef NDEBUG
		SV_DropClient( cl, "DEBUG: illegible client message" );
#endif
		return;
	}

	cl->reliableAcknowledge = MSG_ReadLong( msg );

	// NOTE: when the client message is fux0red the acknowledgement numbers
	// can be out of range, this could cause the server to send thousands of server
	// commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
	if (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) {
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
#ifndef NDEBUG
		SV_DropClient( cl, "DEBUG: illegible client message" );
#endif
		cl->reliableAcknowledge = cl->reliableSequence;
		return;
	}
	// if this is a usercmd from a previous gamestate,
	// ignore it or retransmit the current gamestate
	// 
	// if the client was downloading, let it stay at whatever serverId and
	// gamestate it was at.  This allows it to keep downloading even when
	// the gamestate changes.  After the download is finished, we'll
	// notice and send it a new game state
	//
	// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=536
	// don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to ""
	// but we still need to read the next message to move to next download or send gamestate
	// I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else
	if ( serverId != sv.serverId && !*cl->downloadName && !strstr(cl->lastClientCommandString, "nextdl") ) {
		if ( serverId >= sv.restartedServerId && serverId < sv.serverId ) { // TTimo - use a comparison here to catch multiple map_restart
			// they just haven't caught the map_restart yet
			Com_DPrintf("%s : ignoring pre map_restart / outdated client message\n", cl->name);
			return;
		}
		// if we can tell that the client has dropped the last
		// gamestate we sent them, resend it
		if ( cl->messageAcknowledge > cl->gamestateMessageNum ) {
			Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name );
			SV_SendClientGameState( cl );
		}
		return;
	}

	// this client has acknowledged the new gamestate so it's
	// safe to start sending it the real time again
	if( cl->oldServerTime && serverId == sv.serverId ){
		Com_DPrintf( "%s acknowledged gamestate\n", cl->name );
		cl->oldServerTime = 0;
	}

	// read optional clientCommand strings
	do {
		c = MSG_ReadByte( msg );

		// See if this is an extension command after the EOF, which means we
		//  got data that a legacy server should ignore.
		if ((c == clc_EOF) && (MSG_LookaheadByte( msg ) == clc_extension)) {
			MSG_ReadByte( msg );  // throw the clc_extension byte away.
			c = MSG_ReadByte( msg );  // something legacy servers can't do!
			// sometimes you get a clc_extension at end of stream...dangling
			//  bits in the huffman decoder giving a bogus value?
			if (c == -1) {
				c = clc_EOF;
			}
		}

		if ( c == clc_EOF ) {
			break;
		}

		if ( c != clc_clientCommand ) {
			break;
		}
		if ( !SV_ClientCommand( cl, msg ) ) {
			return;	// we couldn't execute it because of the flood protection
		}
		if (cl->state == CS_ZOMBIE) {
			return;	// disconnect command
		}
	} while ( 1 );

	// read the usercmd_t
	if ( c == clc_move ) {
		SV_UserMove( cl, msg, qtrue );
	} else if ( c == clc_moveNoDelta ) {
		SV_UserMove( cl, msg, qfalse );
	} else if ( c == clc_voip ) {
#ifdef USE_VOIP
		SV_UserVoip( cl, msg );
#endif
	} else if ( c != clc_EOF ) {
		Com_Printf( "WARNING: bad command byte for client %i\n", (int) (cl - svs.clients) );
	}
//	if ( msg->readcount != msg->cursize ) {
//		Com_Printf( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
//	}
}