Example #1
0
int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) {
	int i, index, csnum1, csnum2;

	for ( i = client->reliableSent + 1; i <= client->reliableSequence; i++ ) {
		index = i & ( MAX_RELIABLE_COMMANDS - 1 );
		//
		//if ( !Q_strncmp(cmd, client->reliableCommands[ index ], strlen("cs")) ) {
		if ( !Q_strncmp( cmd, SV_GetReliableCommand( client, index ), strlen( "cs" ) ) ) {
			sscanf( cmd, "cs %i", &csnum1 );
			//sscanf(client->reliableCommands[ index ], "cs %i", &csnum2);
			sscanf( SV_GetReliableCommand( client, index ), "cs %i", &csnum2 );
			if ( csnum1 == csnum2 ) {
				//Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );

				/*
				if ( client->netchan.remoteAddress.type != NA_BOT ) {
					Com_Printf( "WARNING: client %i removed double pending config string %i: %s\n", client-svs.clients, csnum1, cmd );
				}
				*/
				return qtrue;
			}
		}
	}
	return qfalse;
}
Example #2
0
/*
======================
SV_AddServerCommand

The given command will be transmitted to the client, and is guaranteed to
not have future snapshot_t executed before it is executed
======================
*/
void SV_AddServerCommand( client_t *client, const char *cmd ) {
	int index, i;

	client->reliableSequence++;
	// if we would be losing an old command that hasn't been acknowledged,
	// we must drop the connection
	// we check == instead of >= so a broadcast print added by SV_DropClient()
	// doesn't cause a recursive drop client
	if ( client->reliableSequence - client->reliableAcknowledge == MAX_RELIABLE_COMMANDS + 1 ) {
		Com_Printf( "===== pending server commands =====\n" );
		for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {

#if defined RTCW_SP
			//Com_Printf( "cmd %5d: %s\n", i, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
			Com_Printf( "cmd %5d: %s\n", i, SV_GetReliableCommand( client, i & ( MAX_RELIABLE_COMMANDS - 1 ) ) );
#else
			Com_Printf( "cmd %5d: %s\n", i, client->reliableCommands[ i & ( MAX_RELIABLE_COMMANDS - 1 ) ] );
#endif // RTCW_XX

		}
		Com_Printf( "cmd %5d: %s\n", i, cmd );
		SV_DropClient( client, "Server command overflow" );
		return;
	}
	index = client->reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );

#if defined RTCW_SP
	//Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
	SV_AddReliableCommand( client, index, cmd );
#else
	Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
#endif // RTCW_XX

}
Example #3
0
/*
==================
SV_UpdateServerCommandsToClient

(re)send all server commands the client hasn't acknowledged yet
==================
*/
void SV_UpdateServerCommandsToClient( client_t *client, msg_t *msg ) {
	int i;

	// write any unacknowledged serverCommands
	for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {
		MSG_WriteByte( msg, svc_serverCommand );
		MSG_WriteLong( msg, i );
		//MSG_WriteString( msg, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
		MSG_WriteString( msg, SV_GetReliableCommand( client, i & ( MAX_RELIABLE_COMMANDS - 1 ) ) );
	}
	client->reliableSent = client->reliableSequence;
}
Example #4
0
/*
==============
SV_Netchan_Decode

	// first 12 bytes of the data are always:
	long serverId;
	long messageAcknowledge;
	long reliableAcknowledge;

==============
*/
static void SV_Netchan_Decode( client_t *client, msg_t *msg ) {
	int serverId, messageAcknowledge, reliableAcknowledge;
	int i, index, srdc, sbit, soob;
	byte key, *string;

	srdc = msg->readcount;
	sbit = msg->bit;
	soob = msg->oob;

	msg->oob = 0;

	serverId = MSG_ReadLong( msg );
	messageAcknowledge = MSG_ReadLong( msg );
	reliableAcknowledge = MSG_ReadLong( msg );

	msg->oob = soob;
	msg->bit = sbit;
	msg->readcount = srdc;

	string = (byte *)SV_GetReliableCommand( client, reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 ) );
	index = 0;
	//
	key = client->challenge ^ serverId ^ messageAcknowledge;
	for ( i = msg->readcount + SV_DECODE_START; i < msg->cursize; i++ ) {
		// modify the key with the last sent and acknowledged server command
		if ( !string[index] ) {
			index = 0;
		}
		if ( string[index] > 127 || string[index] == '%' ) {
			key ^= '.' << ( i & 1 );
		} else {
			key ^= string[index] << ( i & 1 );
		}
		index++;
		// decode the data with this key
		*( msg->data + i ) = *( msg->data + i ) ^ key;
	}
}
Example #5
0
/*
==================
SV_UserMove

The message usually contains all the movement commands
that were in the last three packets, so that the information
in dropped packets can be recovered.

On very fast clients, there may be multiple usercmd packed into
each of the backup packets.
==================
*/
static void SV_UserMove(client_t *cl, msg_t *msg, qboolean delta)
{
	int i, key;
	int cmdCount;
	usercmd_t nullcmd;
	usercmd_t cmds[MAX_PACKET_USERCMDS];
	usercmd_t   *cmd, *oldcmd;

	if(delta)
	{
		cl->deltaMessage = cl->messageAcknowledge;
	}
	else
	{
		cl->deltaMessage = -1;
	}

	cmdCount = MSG_ReadByte(msg);

	if(cmdCount < 1)
	{
		Com_Printf("cmdCount < 1\n");
		return;
	}

	if(cmdCount > MAX_PACKET_USERCMDS)
	{
		Com_Printf("cmdCount > MAX_PACKET_USERCMDS\n");
		return;
	}

	// use the checksum feed in the key
	key = sv.checksumFeed;
	// also use the message acknowledge
	key ^= cl->messageAcknowledge;
	// also use the last acknowledged server command in the key
	//key ^= Com_HashKey(cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32);
	key ^= Com_HashKey(SV_GetReliableCommand(cl, cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS - 1)), 32);

	memset(&nullcmd, 0, sizeof(nullcmd));
	oldcmd = &nullcmd;

	for(i = 0 ; i < cmdCount ; i++)
	{
		cmd = &cmds[i];
		MSG_ReadDeltaUsercmdKey(msg, key, oldcmd, cmd);
//		MSG_ReadDeltaUsercmd( msg, oldcmd, cmd );
		oldcmd = cmd;
	}

	// save time for ping calculation
	cl->frames[ cl->messageAcknowledge & PACKET_MASK ].messageAcked = svs.time;

	// if this is the first usercmd we have received
	// this gamestate, put the client into the world
	if(cl->state == CS_PRIMED)
	{
		SV_ClientEnterWorld(cl, &cmds[0]);
		// the moves can be processed normaly
	}

	//
	if(sv_pure->integer != 0 && cl->pureAuthentic == 0)
	{
		SV_DropClient(cl, "Cannot validate pure client!");
		return;
	}

	if(cl->state != CS_ACTIVE)
	{
		cl->deltaMessage = -1;
		return;
	}

	// usually, the first couple commands will be duplicates
	// of ones we have previously received, but the servertimes
	// in the commands will cause them to be immediately discarded
	for(i =  0 ; i < cmdCount ; i++)
	{
		// if this is a cmd from before a map_restart ignore it
		if(cmds[i].serverTime > cmds[cmdCount - 1].serverTime)
		{
			continue;
		}

		// extremely lagged or cmd from before a map_restart
		//if ( cmds[i].serverTime > svs.time + 3000 ) {
		//  continue;
		//}
		if(sv_gametype->integer != GT_SINGLE_PLAYER)      // RF, we need to allow this in single player, where loadgame's can cause the player to freeze after reloading if we do this check
		{
			// don't execute if this is an old cmd which is already executed
			// these old cmds are included when cl_packetdup > 0
			if(cmds[i].serverTime <= cl->lastUsercmd.serverTime)        // Q3_MISSIONPACK
			{
//			if ( cmds[i].serverTime > cmds[cmdCount-1].serverTime ) {
				continue;   // from just before a map_restart
			}
		}

		SV_ClientThink(cl, &cmds[ i ]);
	}
}