Exemple #1
0
/*
=============
SV_EmitPacketEntities

Writes a delta update of an entityState_t list to the message.
=============
*/
static void SV_EmitPacketEntities( clientSnapshot_t *from, clientSnapshot_t *to, msg_t *msg ) {
	entityState_t	*oldent, *newent;
	int		oldindex, newindex;
	int		oldnum, newnum;
	int		from_num_entities;

	// generate the delta update
	if ( !from ) {
		from_num_entities = 0;
	} else {
		from_num_entities = from->num_entities;
	}

	newent = NULL;
	oldent = NULL;
	newindex = 0;
	oldindex = 0;
	while ( newindex < to->num_entities || oldindex < from_num_entities ) {
		if ( newindex >= to->num_entities ) {
			newnum = 9999;
		} else {
			newent = &svs.snapshotEntities[(to->first_entity+newindex) % svs.numSnapshotEntities];
			newnum = newent->number;
		}

		if ( oldindex >= from_num_entities ) {
			oldnum = 9999;
		} else {
			oldent = &svs.snapshotEntities[(from->first_entity+oldindex) % svs.numSnapshotEntities];
			oldnum = oldent->number;
		}

		if ( newnum == oldnum ) {
			// delta update from old position
			// because the force parm is qfalse, this will not result
			// in any bytes being emited if the entity has not changed at all
			MSG_WriteDeltaEntity (msg, oldent, newent, qfalse );
			oldindex++;
			newindex++;
			continue;
		}

		if ( newnum < oldnum ) {
			// this is a new entity, send it from the baseline
			MSG_WriteDeltaEntity (msg, &sv.svEntities[newnum].baseline, newent, qtrue );
			newindex++;
			continue;
		}

		if ( newnum > oldnum ) {
			// the old entity isn't present in the new message
			MSG_WriteDeltaEntity (msg, oldent, NULL, qtrue );
			oldindex++;
			continue;
		}
	}

	MSG_WriteBits( msg, (MAX_GENTITIES-1), GENTITYNUM_BITS );	// end of packetentities
}
Exemple #2
0
/*
=============
SV_EmitPacketEntities

Writes a delta update of an entity_state_t list to the message->
=============
*/
void SV_EmitPacketEntities( client_frame_t *from, client_frame_t *to, sizebuf_t *msg )
{
	entity_state_t	*oldent, *newent;
	int		oldindex, newindex;
	int		oldnum, newnum;
	int		from_num_entities;

	MSG_WriteByte( msg, svc_packetentities );

	if( !from ) from_num_entities = 0;
	else from_num_entities = from->num_entities;

	newent = NULL;
	oldent = NULL;
	newindex = 0;
	oldindex = 0;
	while( newindex < to->num_entities || oldindex < from_num_entities )
	{
		if( newindex >= to->num_entities ) newnum = MAX_ENTNUMBER;
		else
		{
			newent = &svs.client_entities[(to->first_entity+newindex)%svs.num_client_entities];
			newnum = newent->number;
		}

		if( oldindex >= from_num_entities ) oldnum = MAX_ENTNUMBER;
		else
		{
			oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities];
			oldnum = oldent->number;
		}

		if( newnum == oldnum )
		{	
			// delta update from old position
			// because the force parm is false, this will not result
			// in any bytes being emited if the entity has not changed at all
			MSG_WriteDeltaEntity( oldent, newent, msg, false, ( newent->number <= sv_maxclients->integer ));
			oldindex++;
			newindex++;
			continue;
		}
		if( newnum < oldnum )
		{	
			// this is a new entity, send it from the baseline
			MSG_WriteDeltaEntity( &svs.baselines[newnum], newent, msg, true, true );
			newindex++;
			continue;
		}
		if( newnum > oldnum )
		{	
			// remove from message
			MSG_WriteDeltaEntity( oldent, NULL, msg, false, false );
			oldindex++;
			continue;
		}
	}
	MSG_WriteBits( msg, 0, "svc_packetentities", NET_WORD ); // end of packetentities
}
Exemple #3
0
void
SV_Baselines_f(void)
{
	int start;
	entity_state_t nullstate;
	entity_state_t *base;

	Com_DPrintf("Baselines() from %s\n", sv_client->name);

	if (sv_client->state != cs_connected)
	{
		Com_Printf("baselines not valid -- already spawned\n");
		return;
	}

	/* handle the case of a level changing while a client was connecting */
	if ((int)strtol(Cmd_Argv(1), (char **)NULL, 10) != svs.spawncount)
	{
		Com_Printf("SV_Baselines_f from different level\n");
		SV_New_f();
		return;
	}

	start = (int)strtol(Cmd_Argv(2), (char **)NULL, 10);
	memset(&nullstate, 0, sizeof(nullstate));

	/* write a packet full of data */
	while (sv_client->netchan.message.cursize < MAX_MSGLEN / 2 &&
		   start < MAX_EDICTS)
	{
		base = &sv.baselines[start];

		if (base->modelindex || base->sound || base->effects)
		{
			MSG_WriteByte(&sv_client->netchan.message, svc_spawnbaseline);
			MSG_WriteDeltaEntity(&nullstate, base,
					&sv_client->netchan.message,
					true, true);
		}

		start++;
	}

	/* send next command */
	if (start == MAX_EDICTS)
	{
		MSG_WriteByte(&sv_client->netchan.message, svc_stufftext);
		MSG_WriteString(&sv_client->netchan.message,
				va("precache %i\n", svs.spawncount));
	}
	else
	{
		MSG_WriteByte(&sv_client->netchan.message, svc_stufftext);
		MSG_WriteString(&sv_client->netchan.message,
				va("cmd baselines %i %i\n", svs.spawncount, start));
	}
}
Exemple #4
0
static void demoFramePack( msg_t *msg, const demoFrame_t *newFrame, const demoFrame_t *oldFrame ) {
	int i;
	/* Full or delta frame marker */
	MSG_WriteBits( msg, oldFrame ? 0 : 1, 1 );
	MSG_WriteLong( msg, newFrame->serverTime );
	/* Add the config strings */
	for (i = 0;i<MAX_CONFIGSTRINGS;i++) {
		const char *oldString = !oldFrame ? "" : &oldFrame->string.data[oldFrame->string.offsets[i]];
		const char *newString = newFrame->string.data + newFrame->string.offsets[i];
		if (strcmp( oldString, newString)) {
			MSG_WriteShort( msg, i );
			MSG_WriteBigString( msg, newString );
		}
	}
	MSG_WriteShort( msg, MAX_CONFIGSTRINGS );
	/* Add the playerstates */
	for (i=0; i<MAX_CLIENTS; i++) {
		const playerState_t *oldPlayer, *newPlayer;
		if (!newFrame->clientData[i])
			continue;
		oldPlayer = (!oldFrame || !oldFrame->clientData[i]) ? &demoNullPlayerState : &oldFrame->clients[i];
		newPlayer = &newFrame->clients[i];
		MSG_WriteByte( msg, i );
		MSG_WriteDeltaPlayerstate( msg, oldPlayer, newPlayer );
	}
	MSG_WriteByte( msg, MAX_CLIENTS );
	/* Add the entities */
	for (i=0; i<MAX_GENTITIES-1; i++) {
		const entityState_t *oldEntity, *newEntity;
		newEntity = &newFrame->entities[i];
		if (oldFrame) {
			oldEntity = &oldFrame->entities[i];
			if (oldEntity->number == (MAX_GENTITIES -1))
				oldEntity = 0;
		} else {
			oldEntity = 0;
		}
		if (newEntity->number != i || newEntity->number >= (MAX_GENTITIES -1)) {
			newEntity = 0;
		} else {
			if (!oldEntity) {
				oldEntity = &demoNullEntityState;
			}
		}
		MSG_WriteDeltaEntity( msg, oldEntity, newEntity, qfalse );
	}
	MSG_WriteBits( msg, (MAX_GENTITIES-1), GENTITYNUM_BITS );
	/* Add the area mask */
	MSG_WriteByte( msg, newFrame->areaUsed );
	MSG_WriteData( msg, newFrame->areamask, newFrame->areaUsed );
	/* Add the command string data */
	MSG_WriteLong( msg, newFrame->commandUsed );
	MSG_WriteData( msg, newFrame->commandData, newFrame->commandUsed );
}
Exemple #5
0
/*
================
SV_SendClientGameState

Sends the first message from the server to a connected client.
This will be sent on the initial connection and upon each new map load.

It will be resent if the client acknowledges a later message but has
the wrong gamestate.
================
*/
void SV_SendClientGameState( client_t *client ) {
	int			start;
	entityState_t	*base, nullstate;
	msg_t		msg;
	byte		msgBuffer[MAX_MSGLEN];

	Com_DPrintf ("SV_SendGameState() for %s\n", client->name);
	client->state = CS_PRIMED;

	// when we receive the first packet from the client, we will
	// notice that it is from a different serverid and that the
	// gamestate message was not just sent, forcing a retransmit
	client->gamestateMessageNum = client->netchan.outgoingSequence;

	// clear the reliable message list for this client
	client->reliableSequence = 0;
	client->reliableAcknowledge = 0;

	MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );

	// send the gamestate
	MSG_WriteByte( &msg, svc_gamestate );
	MSG_WriteLong( &msg, client->reliableSequence );

	// write the configstrings
	for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
		if (sv.configstrings[start][0]) {
			MSG_WriteByte( &msg, svc_configstring );
			MSG_WriteShort( &msg, start );
			MSG_WriteString( &msg, sv.configstrings[start] );
		}
	}

	// write the baselines
	memset( &nullstate, 0, sizeof( nullstate ) );
	for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
		base = &sv.svEntities[start].baseline;
		if ( !base->number ) {
			continue;
		}
		MSG_WriteByte( &msg, svc_baseline );
		MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue );
	}

	MSG_WriteByte( &msg, 0 );

	// check for overflow
	if ( msg.overflowed ) {
		Com_Printf ("WARNING: GameState overflowed for %s\n", client->name);
	}

	// deliver this to the client
	SV_SendMessageToClient( &msg, client );
}
Exemple #6
0
/*
* SV_Baselines_f
*/
static void SV_Baselines_f( client_t *client )
{
	int start;
	entity_state_t nullstate;
	entity_state_t *base;

	Com_DPrintf( "Baselines() from %s\n", client->name );

	if( client->state != CS_CONNECTED )
	{
		Com_Printf( "baselines not valid -- already spawned\n" );
		return;
	}

	// handle the case of a level changing while a client was connecting
	if( atoi( Cmd_Argv( 1 ) ) != svs.spawncount )
	{
		Com_Printf( "SV_Baselines_f from different level\n" );
		SV_New_f( client );
		return;
	}

	start = atoi( Cmd_Argv( 2 ) );
	if( start < 0 )
		start = 0;

	memset( &nullstate, 0, sizeof( nullstate ) );

	// write a packet full of data
	SV_InitClientMessage( client, &tmpMessage, NULL, 0 );

	while( tmpMessage.cursize < FRAGMENT_SIZE * 3 && start < MAX_EDICTS )
	{
		base = &sv.baselines[start];
		if( base->modelindex || base->sound || base->effects )
		{
			MSG_WriteByte( &tmpMessage, svc_spawnbaseline );
			MSG_WriteDeltaEntity( &nullstate, base, &tmpMessage, qtrue, qtrue );
		}
		start++;
	}

	// send next command
	if( start == MAX_EDICTS )
		SV_SendServerCommand( client, "precache %i", svs.spawncount );
	else
		SV_SendServerCommand( client, "cmd baselines %i %i", svs.spawncount, start );

	SV_AddReliableCommandsToMessage( client, &tmpMessage );
	SV_SendMessageToClient( client, &tmpMessage );
}
Exemple #7
0
void SV_CreateClientGameStateMessage( client_t *client, msg_t *msg ) {
	int			start;
	entityState_t	*base, nullstate;

	// NOTE, MRE: all server->client messages now acknowledge
	// let the client know which reliable clientCommands we have received
	MSG_WriteLong( msg, client->lastClientCommand );

	// send any server commands waiting to be sent first.
	// we have to do this cause we send the client->reliableSequence
	// with a gamestate and it sets the clc.serverCommandSequence at
	// the client side
	SV_UpdateServerCommandsToClient( client, msg );

	// send the gamestate
	MSG_WriteByte( msg, svc_gamestate );
	MSG_WriteLong( msg, client->reliableSequence );

	// write the configstrings
	for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
		if (sv.configstrings[start][0]) {
			MSG_WriteByte( msg, svc_configstring );
			MSG_WriteShort( msg, start );
			MSG_WriteBigString( msg, sv.configstrings[start] );
		}
	}

	// write the baselines
	Com_Memset( &nullstate, 0, sizeof( nullstate ) );
	for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
		base = &sv.svEntities[start].baseline;
		if ( !base->number ) {
			continue;
		}
		MSG_WriteByte( msg, svc_baseline );
		MSG_WriteDeltaEntity( msg, &nullstate, base, qtrue );
	}

	MSG_WriteByte( msg, svc_EOF );

	MSG_WriteLong( msg, client - svs.clients);

	// write the checksum feed
	MSG_WriteLong( msg, sv.checksumFeed);

	// For old RMG system.
	MSG_WriteShort ( msg, 0 );
}
Exemple #8
0
/*
==================
SV_WriteBaselineToClient
==================
*/
void SV_WriteBaselineToClient( client_t *client, msg_t *msg ) {
	sharedEntityState_t	*base;
	int					start;

	if ( !client->needBaseline ) {
		return;
	}

	client->needBaseline = qfalse;

	// write the baselines
	for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
		base = (sharedEntityState_t *)DA_ElementPointer( sv.svEntitiesBaseline, start );
		if ( !base->number ) {
			continue;
		}
		MSG_WriteByte( msg, svc_baseline );
		MSG_WriteDeltaEntity( msg, NULL, base, qtrue );
	}
}
Exemple #9
0
void SV_CreateClientGameStateMessage( client_t *client, msg_t *msg, qboolean updateServerCommands ) {
	int			start;
	entityState_t	*base, nullstate;

	// NOTE, MRE: all server->client messages now acknowledge
	// let the client know which reliable clientCommands we have received
	MSG_WriteLong( msg, client->lastClientCommand );

	if ( updateServerCommands ) {
		// send any server commands waiting to be sent first.
		// we have to do this cause we send the client->reliableSequence
		// with a gamestate and it sets the clc.serverCommandSequence at
		// the client side
		SV_UpdateServerCommandsToClient( client, msg );
	}

	// send the gamestate
	MSG_WriteByte( msg, svc_gamestate );
	MSG_WriteLong( msg, client->reliableSequence );

	// write the configstrings
	for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
		if (sv.configstrings[start][0]) {
			MSG_WriteByte( msg, svc_configstring );
			MSG_WriteShort( msg, start );
			MSG_WriteBigString( msg, sv.configstrings[start] );
		}
	}

	// write the baselines
	Com_Memset( &nullstate, 0, sizeof( nullstate ) );
	for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
		base = &sv.svEntities[start].baseline;
		if ( !base->number ) {
			continue;
		}
		MSG_WriteByte( msg, svc_baseline );
		MSG_WriteDeltaEntity( msg, &nullstate, base, qtrue );
	}

	MSG_WriteByte( msg, svc_EOF );

	MSG_WriteLong( msg, client - svs.clients);

	// write the checksum feed
	MSG_WriteLong( msg, sv.checksumFeed);

	//rwwRMG - send info for the terrain
	if ( TheRandomMissionManager )
	{
		z_stream zdata;

		// Send the height map
		memset(&zdata, 0, sizeof(z_stream));
		deflateInit ( &zdata, Z_BEST_COMPRESSION );

		unsigned char heightmap[15000];
		zdata.next_out = (unsigned char*)heightmap;
		zdata.avail_out = 15000;
		zdata.next_in = TheRandomMissionManager->GetLandScape()->GetHeightMap();
		zdata.avail_in = TheRandomMissionManager->GetLandScape()->GetRealArea();
		deflate(&zdata, Z_SYNC_FLUSH);

		MSG_WriteShort ( msg, (unsigned short)zdata.total_out );
		MSG_WriteBits ( msg, 1, 1 );
		MSG_WriteData ( msg, heightmap, zdata.total_out);

		deflateEnd(&zdata);

		// Send the flatten map
		memset(&zdata, 0, sizeof(z_stream));
		deflateInit ( &zdata, Z_BEST_COMPRESSION );

		zdata.next_out = (unsigned char*)heightmap;
		zdata.avail_out = 15000;
		zdata.next_in = TheRandomMissionManager->GetLandScape()->GetFlattenMap();
		zdata.avail_in = TheRandomMissionManager->GetLandScape()->GetRealArea();
		deflate(&zdata, Z_SYNC_FLUSH);

		MSG_WriteShort ( msg, (unsigned short)zdata.total_out );
		MSG_WriteBits ( msg, 1, 1 );
		MSG_WriteData ( msg, heightmap, zdata.total_out);

		deflateEnd(&zdata);

		// Seed is needed for misc ents and noise
		MSG_WriteLong ( msg, TheRandomMissionManager->GetLandScape()->get_rand_seed ( ) );

		SV_WriteRMGAutomapSymbols ( msg );
	}
	else
	{
		MSG_WriteShort ( msg, 0 );
	}
}
Exemple #10
0
/*
Start a server-side demo.

This does it all, create the file and adjust the demo-related
stuff in client_t.

This is mostly ripped from sv_client.c/SV_SendClientGameState
and cl_main.c/CL_Record_f.
*/
static void SVD_StartDemoFile(client_t *client, const char *path)
{
        int             i, len;
        entityState_t   *base, nullstate;
        msg_t           msg;
        byte            buffer[MAX_MSGLEN];
        fileHandle_t    file;

        Com_DPrintf("SVD_StartDemoFile\n");
        assert(!client->demo_recording);

        // create the demo file and write the necessary header
        file = FS_FOpenFileWrite(path);
        assert(file != 0);

        MSG_Init(&msg, buffer, sizeof(buffer));
        MSG_Bitstream(&msg); // XXX server code doesn't do this, client code does

        MSG_WriteLong(&msg, client->lastClientCommand); // TODO: or is it client->reliableSequence?

        MSG_WriteByte(&msg, svc_gamestate);
        MSG_WriteLong(&msg, client->reliableSequence);

        for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
                if (sv.configstrings[i][0]) {
                        MSG_WriteByte(&msg, svc_configstring);
                        MSG_WriteShort(&msg, i);
                        MSG_WriteBigString(&msg, sv.configstrings[i]);
                }
        }

        Com_Memset(&nullstate, 0, sizeof(nullstate));
        for (i = 0 ; i < MAX_GENTITIES; i++) {
                base = &sv.svEntities[i].baseline;
                if (!base->number) {
                        continue;
                }
                MSG_WriteByte(&msg, svc_baseline);
                MSG_WriteDeltaEntity(&msg, &nullstate, base, qtrue);
        }

        MSG_WriteByte(&msg, svc_EOF);

        MSG_WriteLong(&msg, client - svs.clients);
        MSG_WriteLong(&msg, sv.checksumFeed);

        MSG_WriteByte(&msg, svc_EOF); // XXX server code doesn't do this, SV_Netchan_Transmit adds it!

        len = LittleLong(client->netchan.outgoingSequence-1);
        FS_Write(&len, 4, file);

        len = LittleLong (msg.cursize);
        FS_Write(&len, 4, file);
        FS_Write(msg.data, msg.cursize, file);

        FS_Flush(file);

        // adjust client_t to reflect demo started
        client->demo_recording = qtrue;
        client->demo_file = file;
        client->demo_waiting = qtrue;
        client->demo_backoff = 1;
        client->demo_deltas = 0;
}
/*
================
SV_SendClientGameState

Sends the first message from the server to a connected client.
This will be sent on the initial connection and upon each new map load.

It will be resent if the client acknowledges a later message but has
the wrong gamestate.
================
*/
void SV_SendClientGameState( client_t *client )
{
	int           start;
	entityState_t *base, nullstate;
	msg_t         msg;
	byte          msgBuffer[ MAX_MSGLEN ];

	Log::Debug( "SV_SendClientGameState() for %s", client->name );
	Log::Debug( "Going from CS_CONNECTED to CS_PRIMED for %s", client->name );
	client->state = clientState_t::CS_PRIMED;

	// when we receive the first packet from the client, we will
	// notice that it is from a different serverid and that the
	// gamestate message was not just sent, forcing a retransmit
	client->gamestateMessageNum = client->netchan.outgoingSequence;

	MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );

	// NOTE, MRE: all server->client messages now acknowledge
	// let the client know which reliable clientCommands we have received
	MSG_WriteLong( &msg, client->lastClientCommand );

	// send any server commands waiting to be sent first.
	// we have to do this cause we send the client->reliableSequence
	// with a gamestate and it sets the clc.serverCommandSequence at
	// the client side
	SV_UpdateServerCommandsToClient( client, &msg );

	// send the gamestate
	MSG_WriteByte( &msg, svc_gamestate );
	MSG_WriteLong( &msg, client->reliableSequence );

	// write the configstrings
	for ( start = 0; start < MAX_CONFIGSTRINGS; start++ )
	{
		if ( sv.configstrings[ start ][ 0 ] )
		{
			MSG_WriteByte( &msg, svc_configstring );
			MSG_WriteShort( &msg, start );
			MSG_WriteBigString( &msg, sv.configstrings[ start ] );
		}
	}

	// write the baselines
	memset( &nullstate, 0, sizeof( nullstate ) );

	for ( start = 0; start < MAX_GENTITIES; start++ )
	{
		base = &sv.svEntities[ start ].baseline;

		if ( !base->number )
		{
			continue;
		}

		MSG_WriteByte( &msg, svc_baseline );
		MSG_WriteDeltaEntity( &msg, &nullstate, base, true );
	}

	MSG_WriteByte( &msg, svc_EOF );

	MSG_WriteLong( &msg, client - svs.clients );

	// write the checksum feed
	MSG_WriteLong( &msg, sv.checksumFeed );

	// NERVE - SMF - debug info
	Log::Debug( "Sending %i bytes in gamestate to client: %li", msg.cursize, ( long )( client - svs.clients ) );

	// deliver this to the client
	SV_SendMessageToClient( &msg, client );
}
Exemple #12
0
/*
================
SV_SendClientGameState

Sends the first message from the server to a connected client.
This will be sent on the initial connection and upon each new map load.

It will be resent if the client acknowledges a later message but has
the wrong gamestate.
================
*/
void SV_SendClientGameState( client_t *client ) {
	int			start;
	entityState_t	*base, nullstate;
	msg_t		msg;
	byte		msgBuffer[MAX_MSGLEN];

	// MW - my attempt to fix illegible server message errors caused by 
	// packet fragmentation of initial snapshot.
	while(client->state&&client->netchan.unsentFragments)
	{
		// send additional message fragments if the last message
		// was too large to send at once
	
		Com_Printf ("[ISM]SV_SendClientGameState() [2] for %s, writing out old fragments\n", client->name);
		SV_Netchan_TransmitNextFragment(&client->netchan);
	}

	Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name);
	Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name );
	client->state = CS_PRIMED;
	client->pureAuthentic = 0;

	// when we receive the first packet from the client, we will
	// notice that it is from a different serverid and that the
	// gamestate message was not just sent, forcing a retransmit
	client->gamestateMessageNum = client->netchan.outgoingSequence;

	MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );

	// NOTE, MRE: all server->client messages now acknowledge
	// let the client know which reliable clientCommands we have received
	MSG_WriteLong( &msg, client->lastClientCommand );

	// send any server commands waiting to be sent first.
	// we have to do this cause we send the client->reliableSequence
	// with a gamestate and it sets the clc.serverCommandSequence at
	// the client side
	SV_UpdateServerCommandsToClient( client, &msg );

	// send the gamestate
	MSG_WriteByte( &msg, svc_gamestate );
	MSG_WriteLong( &msg, client->reliableSequence );

	// write the configstrings
	for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
		if (sv.configstrings[start][0]) {
			MSG_WriteByte( &msg, svc_configstring );
			MSG_WriteShort( &msg, start );
			MSG_WriteBigString( &msg, sv.configstrings[start] );
		}
	}

	// write the baselines
	Com_Memset( &nullstate, 0, sizeof( nullstate ) );
	for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
		base = &sv.svEntities[start].baseline;
		if ( !base->number ) {
			continue;
		}
		MSG_WriteByte( &msg, svc_baseline );
		MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue );
	}

	MSG_WriteByte( &msg, svc_EOF );

	MSG_WriteLong( &msg, client - svs.clients);

	// write the checksum feed
	MSG_WriteLong( &msg, sv.checksumFeed);

	//rwwRMG - send info for the terrain
	if ( TheRandomMissionManager )
	{
		z_stream zdata;

		// Send the height map
		memset(&zdata, 0, sizeof(z_stream));
		deflateInit ( &zdata, Z_MAX_COMPRESSION );

		unsigned char heightmap[15000];
		zdata.next_out = (unsigned char*)heightmap;
		zdata.avail_out = 15000;
		zdata.next_in = TheRandomMissionManager->GetLandScape()->GetHeightMap();
		zdata.avail_in = TheRandomMissionManager->GetLandScape()->GetRealArea();
		deflate(&zdata, Z_SYNC_FLUSH);

		MSG_WriteShort ( &msg, (unsigned short)zdata.total_out );
		MSG_WriteBits ( &msg, 1, 1 );
		MSG_WriteData ( &msg, heightmap, zdata.total_out);

		deflateEnd(&zdata);

		// Send the flatten map
		memset(&zdata, 0, sizeof(z_stream));
		deflateInit ( &zdata, Z_MAX_COMPRESSION );

		zdata.next_out = (unsigned char*)heightmap;
		zdata.avail_out = 15000;
		zdata.next_in = TheRandomMissionManager->GetLandScape()->GetFlattenMap();
		zdata.avail_in = TheRandomMissionManager->GetLandScape()->GetRealArea();
		deflate(&zdata, Z_SYNC_FLUSH);

		MSG_WriteShort ( &msg, (unsigned short)zdata.total_out );
		MSG_WriteBits ( &msg, 1, 1 );
		MSG_WriteData ( &msg, heightmap, zdata.total_out);

		deflateEnd(&zdata);

		// Seed is needed for misc ents and noise
		MSG_WriteLong ( &msg, TheRandomMissionManager->GetLandScape()->get_rand_seed ( ) );

		SV_WriteRMGAutomapSymbols ( &msg );
	}
	else
	{
		MSG_WriteShort ( &msg, 0 );
	}

	// deliver this to the client
	SV_SendMessageToClient( &msg, client );
}
Exemple #13
0
/*
==================
SV_Baselines_f
==================
*/
void SV_Baselines_f (void)
{
	int				startPos, start;
	int				maxLen;	// Knightmare added
	entity_state_t	nullstate;
	entity_state_t	*base;

	Com_DPrintf ("Baselines() from %s\n", sv_client->name);

	if (sv_client->state != cs_connected)
	{
		Com_Printf ("baselines not valid -- already spawned\n");
		return;
	}
	
	// handle the case of a level changing while a client was connecting
	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
	{
		Com_Printf ("SV_Baselines_f from different level\n");
		SV_New_f ();
		return;
	}

	//	Knightmare- use sv_baselines_maxlen for proper bounding in multiplayer
	maxLen = SV_SetMaxBaselinesSize();

//	start = atoi(Cmd_Argv(2));
	startPos = atoi(Cmd_Argv(2));
	if (startPos < 0) // r1ch's fix for negative index
	{
		Com_Printf ("Illegal baselines request (negative index) from %s[%s], dropping client\n", sv_client->name, NET_AdrToString(sv_client->netchan.remote_address));
		SV_DropClient (sv_client);
		return;
	}
	start = startPos;

	memset (&nullstate, 0, sizeof(nullstate));

	// write a packet full of data
	//	Knightmare- use maxLen for proper bounding
//	while ( sv_client->netchan.message.cursize <  MAX_MSGLEN/2 && start < MAX_EDICTS)
	while ( sv_client->netchan.message.cursize < maxLen && start < MAX_EDICTS)
	{
		base = &sv.baselines[start];
		if (base->modelindex || base->sound || base->effects)
		{
			MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline);
			MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true);
		}
		start++;
	}

	// send next command

	if (start == MAX_EDICTS)
	{
		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
		MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) );
	}
	else
	{
		MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
		MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) );
	}
}
Exemple #14
0
/*
====================
CL_Record_f

record <slot> [<demoname>]

Begins recording a demo from the current position
====================
*/
void CL_Record( client_t	*cl, char *s ) {
	char		name[MAX_OSPATH];
	char		name_zip[MAX_OSPATH];
	byte		bufData[MAX_MSGLEN];
	msg_t	buf;
	int			i;
	int			len;
	entityState_t	*ent;
	entityState_t	nullstate;
	int         clientnum;
	char	*guid;
	char	prefix[MAX_OSPATH];

	clientnum = cl - svs.clients;

	if ( cl->demorecording ) {
		Com_Printf ("Already recording client %i.\n", clientnum);
		return;
	}

//	if ( cl->state != CA_ACTIVE ) {
//		Com_Printf ("You must be in a level to record.\n");
//		return;
//	}
//  // sync 0 doesn't prevent recording, so not forcing it off .. everyone does g_sync 1 ; record ; g_sync 0 ..
//	if ( NET_IsLocalAddress( cl->serverAddress ) && !Cvar_VariableValue( "g_synchronousClients" ) ) {
//		Com_Printf (S_COLOR_YELLOW "WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\n");
//	}

	if ( s ) {
		Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", s, PROTOCOL_VERSION );
	} else {
		int		number,n,a,b,c,d;
		guid = Info_ValueForKey(cl->userinfo, "cl_guid");
		if (!Q_stricmp(guid, "")) {
			guid = "LONGGONE";
		}
		Q_strncpyz(prefix, guid, 9);

		// scan for a free demo name
		for ( number = 0 ; number <= 9999 ; number++ ) {
			if(number < 0 || number > 9999)
				number = 9999;
			n = number;
			a = n / 1000;
			n -= a*1000;
			b = n / 100;
			n -= b*100;
			c = n / 10;
			n -= c*10;
			d = n;

			Com_sprintf (name, sizeof(name), "demos/%s_%s_%i%i%i%i.dm_%d", prefix, sv_mapname->string, a, b, c, d, PROTOCOL_VERSION );
			Com_sprintf (name_zip, sizeof(name_zip), "demos/%s_%s_%i%i%i%i.dm_%d.zip", prefix, sv_mapname->string, a, b, c, d, PROTOCOL_VERSION );
			Q_strlwr(name);
			Q_strlwr(name_zip);
			if (!FS_FileExists(name) && !FS_FileExists(name_zip)) {
				break;	// file doesn't exist
			}
		}
	}

	// open the demo file

	if (!sv_autorecord->integer) {
		Com_Printf ("recording client %i to %s.\n", clientnum, name);
	} else {
		Com_Printf ("Record: %i: %s\n", clientnum, name);
	}

	cl->demofile = FS_FOpenFileWrite( name );
	if ( !cl->demofile ) {
		Com_Printf ("ERROR: couldn't open.\n");
		return;
	}
	// don't start saving messages until a non-delta compressed message is received
	cl->demowaiting = qtrue;
	cl->savedemo = qfalse; // demo will not be saved if sv_autorecord 1 and cl's score is too low

	Q_strncpyz( cl->demoName, name, sizeof( cl->demoName ) );

	// write out the gamestate message
	MSG_Init (&buf, bufData, sizeof(bufData));
	MSG_Bitstream(&buf);

	// NOTE, MRE: all server->client messages now acknowledge
	MSG_WriteLong( &buf, cl->lastClientCommand );// 0007 - 000A

	MSG_WriteByte (&buf, svc_gamestate);// 000B
	MSG_WriteLong (&buf, cl->reliableSequence );// 000C - 000F


	// write the configstrings
	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
		if (sv.configstrings[i][0]) {
			MSG_WriteByte( &buf, svc_configstring );
			MSG_WriteShort( &buf, i );
			MSG_WriteBigString( &buf, sv.configstrings[i] );
		}
	}

	// write the baselines
	Com_Memset( &nullstate, 0, sizeof( nullstate ) );
	for ( i = 0 ; i < MAX_GENTITIES; i++ ) {
		ent = &sv.svEntities[i].baseline;
		if ( !ent->number ) {
			continue;
		}
		MSG_WriteByte( &buf, svc_baseline );
		MSG_WriteDeltaEntity( &buf, &nullstate, ent, qtrue );
	}

	MSG_WriteByte( &buf, svc_EOF );

	// finished writing the gamestate stuff

	// write the client num
	MSG_WriteLong(&buf, clientnum);
	// write the checksum feed
	MSG_WriteLong(&buf, sv.checksumFeed);

	// finished writing the client packet
	MSG_WriteByte( &buf, svc_EOF );

	// write it to the demo file
	len = LittleLong( cl->netchan.outgoingSequence-1 );
	FS_Write (&len, 4, cl->demofile);// 0000 - 0003

	len = LittleLong (buf.cursize);
	FS_Write (&len, 4, cl->demofile);// 0004 - 0007
	FS_Write (buf.data, buf.cursize, cl->demofile);// 0007 - ...

	// the rest of the demo file will be copied from net messages
	cl->demorecording = qtrue;
}
/*
Start a server-side demo.

This does it all, create the file and adjust the demo-related
stuff in client_t.

This is mostly ripped from sv_client.c/SV_SendClientGameState
and cl_main.c/CL_Record_f.
*/
static void SVD_StartDemoFile(client_t *client, const char *path)
{
	int		i, len;
	entityState_t	*base, nullstate;
	msg_t		msg;
	byte		buffer[MAX_MSGLEN];
	fileHandle_t	file;
#ifdef USE_DEMO_FORMAT_42
	char		*s;
	int			v, size;
#endif

	Com_DPrintf("SVD_StartDemoFile\n");
	assert(!client->demo_recording);

	// create the demo file and write the necessary header
	file = FS_FOpenFileWrite(path);
	assert(file != 0);
	
	/* File_write_header_demo // ADD this fx */
	/* HOLBLIN  entete demo */ 
	#ifdef USE_DEMO_FORMAT_42
		//@Barbatos: get the mod version from the server
		s = Cvar_VariableString("g_modversion");
	
		size = strlen( s );
		len = LittleLong( size );
		FS_Write( &len, 4, file );
		FS_Write( s , size ,  file );
		
		v = LittleLong( PROTOCOL_VERSION );
		FS_Write ( &v, 4 , file );
		
		len = 0;
		len = LittleLong( len );
		FS_Write ( &len, 4 , file );
		FS_Write ( &len, 4 , file );
	#endif
	/* END HOLBLIN  entete demo */ 

	MSG_Init(&msg, buffer, sizeof(buffer));
	MSG_Bitstream(&msg); // XXX server code doesn't do this, client code does

	MSG_WriteLong(&msg, client->lastClientCommand); // TODO: or is it client->reliableSequence?

	MSG_WriteByte(&msg, svc_gamestate);
	MSG_WriteLong(&msg, client->reliableSequence);

	for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
		if (sv.configstrings[i][0]) {
			MSG_WriteByte(&msg, svc_configstring);
			MSG_WriteShort(&msg, i);
			MSG_WriteBigString(&msg, sv.configstrings[i]);
		}
	}

	Com_Memset(&nullstate, 0, sizeof(nullstate));
	for (i = 0 ; i < MAX_GENTITIES; i++) {
		base = &sv.svEntities[i].baseline;
		if (!base->number) {
			continue;
		}
		MSG_WriteByte(&msg, svc_baseline);
		MSG_WriteDeltaEntity(&msg, &nullstate, base, qtrue);
	}

	MSG_WriteByte(&msg, svc_EOF);

	MSG_WriteLong(&msg, client - svs.clients);
	MSG_WriteLong(&msg, sv.checksumFeed);

	MSG_WriteByte(&msg, svc_EOF); // XXX server code doesn't do this, SV_Netchan_Transmit adds it!

	len = LittleLong(client->netchan.outgoingSequence-1);
	FS_Write(&len, 4, file);

	len = LittleLong (msg.cursize);
	FS_Write(&len, 4, file);
	FS_Write(msg.data, msg.cursize, file);

	#ifdef USE_DEMO_FORMAT_42
		// add size of packet in the end for backward play /* holblin */
		FS_Write(&len, 4, file);
	#endif

	FS_Flush(file);

	// adjust client_t to reflect demo started
	client->demo_recording = qtrue;
	client->demo_file = file;
	client->demo_waiting = qtrue;
	client->demo_backoff = 1;
	client->demo_deltas = 0;
}
/*
* TV_Downstream_Baselines_f
*/
static void TV_Downstream_Baselines_f( client_t *client )
{
	int start;
	entity_state_t nullstate;
	msg_t message;
	uint8_t messageData[MAX_MSGLEN];

	if( client->state != CS_CONNECTED )
		return;

	// relay is not ready yet
	if( client->relay && client->relay->state < CA_ACTIVE )
	{
		TV_Downstream_SendServerCommand( client, "reconnect" );
		return;
	}

	// handle the case of a level changing while a client was connecting
	if( atoi( Cmd_Argv( 1 ) ) != ( client->relay ? client->relay->servercount : tvs.lobby.spawncount ) )
	{
		TV_Downstream_New_f( client );
		return;
	}

	if( !client->relay )
	{
		TV_Downstream_SendServerCommand( client, "precache %i", tvs.lobby.spawncount );
		return;
	}

	start = atoi( Cmd_Argv( 2 ) );
	if( start < 0 )
		start = 0;

	memset( &nullstate, 0, sizeof( nullstate ) );

	// write a packet full of data
	TV_Downstream_InitClientMessage( client, &message, messageData, sizeof( messageData ) );

	while( message.cursize < FRAGMENT_SIZE * 3 && start < MAX_EDICTS )
	{
		if( client->relay->baselines[start].number )
		{
			MSG_WriteByte( &message, svc_spawnbaseline );
			MSG_WriteDeltaEntity( &nullstate, &client->relay->baselines[start], &message, true, true );
		}
		start++;
	}

	// send next command
	if( start == MAX_EDICTS )
	{
		TV_Downstream_SendServerCommand( client, "precache %i", client->relay->servercount );
	}
	else
	{
		TV_Downstream_SendServerCommand( client, "cmd baselines %i %i", client->relay->servercount, start );
	}

	TV_Downstream_AddReliableCommandsToMessage( client, &message );
	TV_Downstream_SendMessageToClient( client, &message );
}
Exemple #17
0
void demoCutWriteDemoHeader(fileHandle_t f, clientConnection_t *clcCut, clientActive_t *clCut) {
	byte			bufData[MAX_MSGLEN];
	msg_t			buf;
	int				i;
	int				len;
	entityState_t	*ent;
	entityState_t	nullstate;
	char			*s;
	// write out the gamestate message
	MSG_Init(&buf, bufData, sizeof(bufData));
	MSG_Bitstream(&buf);
	// NOTE, MRE: all server->client messages now acknowledge
	MSG_WriteLong(&buf, clcCut->reliableSequence);
	MSG_WriteByte(&buf, svc_gamestate);
	MSG_WriteLong(&buf, clcCut->serverCommandSequence);
	// configstrings
	for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
		if (!clCut->gameState.stringOffsets[i]) {
			continue;
		}
		s = clCut->gameState.stringData + clCut->gameState.stringOffsets[i];
		MSG_WriteByte(&buf, svc_configstring);
		MSG_WriteShort(&buf, i);
		MSG_WriteBigString(&buf, s);
	}
	// baselines
	Com_Memset(&nullstate, 0, sizeof(nullstate));
	for (i = 0; i < MAX_GENTITIES ; i++) {
		ent = &clCut->entityBaselines[i];
		if ( !ent->number ) {
			continue;
		}
		MSG_WriteByte(&buf, svc_baseline);
		MSG_WriteDeltaEntity(&buf, &nullstate, ent, qtrue);
	}
	MSG_WriteByte(&buf, svc_EOF);
	// finished writing the gamestate stuff
	// write the client num
	MSG_WriteLong(&buf, clcCut->clientNum);
	// write the checksum feed
	MSG_WriteLong(&buf, clcCut->checksumFeed);
	// RMG stuff
	if ( clcCut->rmgHeightMapSize ) {
		// Height map
		MSG_WriteShort(&buf, (unsigned short)clcCut->rmgHeightMapSize);
		MSG_WriteBits(&buf, 0, 1 );
		MSG_WriteData(&buf, clcCut->rmgHeightMap, clcCut->rmgHeightMapSize);
		// Flatten map
		MSG_WriteShort(&buf, (unsigned short)clcCut->rmgHeightMapSize);
		MSG_WriteBits(&buf, 0, 1 );
		MSG_WriteData(&buf, clcCut->rmgFlattenMap, clcCut->rmgHeightMapSize);
		// Seed
		MSG_WriteLong (&buf, clcCut->rmgSeed);
		// Automap symbols
		MSG_WriteShort (&buf, (unsigned short)clcCut->rmgAutomapSymbolCount);
		for (i = 0; i < clcCut->rmgAutomapSymbolCount; i ++) {
			MSG_WriteByte(&buf, (unsigned char)clcCut->rmgAutomapSymbols[i].mType);
			MSG_WriteByte(&buf, (unsigned char)clcCut->rmgAutomapSymbols[i].mSide);
			MSG_WriteLong(&buf, (long)clcCut->rmgAutomapSymbols[i].mOrigin[0]);
			MSG_WriteLong(&buf, (long)clcCut->rmgAutomapSymbols[i].mOrigin[1]);
		}
	} else {
		MSG_WriteShort (&buf, 0);
	}
	// finished writing the client packet
	MSG_WriteByte(&buf, svc_EOF);
	// write it to the demo file
	len = LittleLong(clcCut->serverMessageSequence - 1);
	FS_Write(&len, 4, f);
	len = LittleLong(buf.cursize);
	FS_Write(&len, 4, f);
	FS_Write(buf.data, buf.cursize, f);
}
Exemple #18
0
void CL_Record(const char *name)
{
	int           i;
	msg_t         buf;
	byte          bufData[MAX_MSGLEN];
	entityState_t *ent;
	entityState_t nullstate;
	char          *s;
	int           len;

	// open the demo file
	Com_FuncPrinf("Recording to %s.\n", name);
	clc.demofile = FS_FOpenFileWrite(name);
	if (!clc.demofile)
	{
		Com_FuncPrinf("ERROR: couldn't open.\n");
		return;
	}

	clc.demorecording = qtrue;
	Cvar_Set("cl_demorecording", "1");    // fretn
	Q_strncpyz(clc.demoName, demoName, sizeof(clc.demoName));
	Cvar_Set("cl_demofilename", clc.demoName);    // bani
	Cvar_Set("cl_demooffset", "0");    // bani

	// don't start saving messages until a non-delta compressed message is received
	clc.demowaiting = qtrue;

	// write out the gamestate message
	MSG_Init(&buf, bufData, sizeof(bufData));
	MSG_Bitstream(&buf);

	// NOTE: all server->client messages now acknowledge
	MSG_WriteLong(&buf, clc.reliableSequence);

	MSG_WriteByte(&buf, svc_gamestate);
	MSG_WriteLong(&buf, clc.serverCommandSequence);

	// configstrings
	for (i = 0; i < MAX_CONFIGSTRINGS; i++)
	{
		if (!cl.gameState.stringOffsets[i])
		{
			continue;
		}
		s = cl.gameState.stringData + cl.gameState.stringOffsets[i];
		MSG_WriteByte(&buf, svc_configstring);
		MSG_WriteShort(&buf, i);
		MSG_WriteBigString(&buf, s);
	}

	// baselines
	memset(&nullstate, 0, sizeof(nullstate));
	for (i = 0; i < MAX_GENTITIES; i++)
	{
		ent = &cl.entityBaselines[i];
		if (!ent->number)
		{
			continue;
		}
		MSG_WriteByte(&buf, svc_baseline);
		MSG_WriteDeltaEntity(&buf, &nullstate, ent, qtrue);
	}

	MSG_WriteByte(&buf, svc_EOF);

	// finished writing the gamestate stuff

	// write the client num
	MSG_WriteLong(&buf, clc.clientNum);
	// write the checksum feed
	MSG_WriteLong(&buf, clc.checksumFeed);

	// finished writing the client packet
	MSG_WriteByte(&buf, svc_EOF);

	// write it to the demo file
	len = LittleLong(clc.serverMessageSequence - 1);
	FS_Write(&len, 4, clc.demofile);

	len = LittleLong(buf.cursize);
	FS_Write(&len, 4, clc.demofile);
	FS_Write(buf.data, buf.cursize, clc.demofile);

	// the rest of the demo file will be copied from net messages
}
Exemple #19
0
/*
================
SV_SendClientGameState

Sends the first message from the server to a connected client.
This will be sent on the initial connection and upon each new map load.

It will be resent if the client acknowledges a later message but has
the wrong gamestate.
================
*/
void SV_SendClientGameState( client_t *client ) {
	int			start;
	entityState_t	*base, nullstate;
	msg_t		msg;
	byte		msgBuffer[MAX_MSGLEN];

	// MW - my attempt to fix illegible server message errors caused by 
	// packet fragmentation of initial snapshot.
	while(client->state&&client->netchan.unsentFragments)
	{
		// send additional message fragments if the last message
		// was too large to send at once
	
		Com_Printf ("[ISM]SV_SendClientGameState() [2] for %s, writing out old fragments\n", client->name);
		SV_Netchan_TransmitNextFragment(&client->netchan);
	}

	Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name);
	Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name );
	client->state = CS_PRIMED;
	client->pureAuthentic = 0;

	// when we receive the first packet from the client, we will
	// notice that it is from a different serverid and that the
	// gamestate message was not just sent, forcing a retransmit
	client->gamestateMessageNum = client->netchan.outgoingSequence;

	MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );

	// NOTE, MRE: all server->client messages now acknowledge
	// let the client know which reliable clientCommands we have received
	MSG_WriteLong( &msg, client->lastClientCommand );

	// send any server commands waiting to be sent first.
	// we have to do this cause we send the client->reliableSequence
	// with a gamestate and it sets the clc.serverCommandSequence at
	// the client side
	SV_UpdateServerCommandsToClient( client, &msg );

	// send the gamestate
	MSG_WriteByte( &msg, svc_gamestate );
	MSG_WriteLong( &msg, client->reliableSequence );

	// write the configstrings
	for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
		if (sv.configstrings[start][0]) {
			MSG_WriteByte( &msg, svc_configstring );
			MSG_WriteShort( &msg, start );
			MSG_WriteBigString( &msg, sv.configstrings[start] );
		}
	}

	// write the baselines
	Com_Memset( &nullstate, 0, sizeof( nullstate ) );
	for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
		base = &sv.svEntities[start].baseline;
		if ( !base->number ) {
			continue;
		}
		MSG_WriteByte( &msg, svc_baseline );
		MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue );
	}

	MSG_WriteByte( &msg, svc_EOF );

	MSG_WriteLong( &msg, client - svs.clients);

	// write the checksum feed
	MSG_WriteLong( &msg, sv.checksumFeed);

	// deliver this to the client
	SV_SendMessageToClient( &msg, client );
}
Exemple #20
0
/*
================
SV_SendClientGameState

Sends the first message from the server to a connected client.
This will be sent on the initial connection and upon each new map load.

It will be resent if the client acknowledges a later message but has
the wrong gamestate.
================
*/
static void SV_SendClientGameState( client_t *client ) {
	int			start;
	entityState_t	*base, nullstate;
	msg_t		msg;
	byte		msgBuffer[MAX_MSGLEN];

 	Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name);
	Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name );
	client->state = CS_PRIMED;
	client->pureAuthentic = 0;
	client->gotCP = qfalse;

	// when we receive the first packet from the client, we will
	// notice that it is from a different serverid and that the
	// gamestate message was not just sent, forcing a retransmit
	client->gamestateMessageNum = client->netchan.outgoingSequence;

	MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) );

	// NOTE, MRE: all server->client messages now acknowledge
	// let the client know which reliable clientCommands we have received
	MSG_WriteLong( &msg, client->lastClientCommand );

	// send any server commands waiting to be sent first.
	// we have to do this cause we send the client->reliableSequence
	// with a gamestate and it sets the clc.serverCommandSequence at
	// the client side
	SV_UpdateServerCommandsToClient( client, &msg );

	// send the gamestate
	MSG_WriteByte( &msg, svc_gamestate );
	MSG_WriteLong( &msg, client->reliableSequence );

	// write the configstrings
	for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) {
		if (sv.configstrings[start][0]) {
			MSG_WriteByte( &msg, svc_configstring );
			MSG_WriteShort( &msg, start );
			MSG_WriteBigString( &msg, sv.configstrings[start] );
		}
	}

	// write the baselines
	Com_Memset( &nullstate, 0, sizeof( nullstate ) );
	for ( start = 0 ; start < MAX_GENTITIES; start++ ) {
		base = &sv.svEntities[start].baseline;
		if ( !base->number ) {
			continue;
		}
		MSG_WriteByte( &msg, svc_baseline );
		MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue );
	}

	MSG_WriteByte( &msg, svc_EOF );

	MSG_WriteLong( &msg, client - svs.clients);

	// write the checksum feed
	MSG_WriteLong( &msg, sv.checksumFeed);

	// There's something unknown going on here at the moment.
	// For now we're just going with default of adding a 0 short to keep jampded compatability.
	MSG_WriteShort( &msg, 0);

	// deliver this to the client
	SV_SendMessageToClient( &msg, client );
}
Exemple #21
0
/*
====================
CL_Record_f

record <demoname>

Begins recording a demo from the current position
====================
*/
void CL_Record_f (void)
{
	char	name[MAX_OSPATH];
	char	buf_data[MAX_MSGLEN];
	sizebuf_t	buf;
	int		i;
	int		len;
	entity_state_t	*ent;
	entity_state_t	nullstate;

	if (Cmd_Argc() != 2)
	{
		Com_Printf ("record <demoname>\n");
		return;
	}

	if (cls.demorecording)
	{
		Com_Printf ("Already recording.\n");
		return;
	}

	if (cls.state != ca_active)
	{
		Com_Printf ("You must be in a level to record.\n");
		return;
	}

	//
	// open the demo file
	//
	Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));

	Com_Printf ("recording to %s.\n", name);
	FS_CreatePath (name);
	cls.demofile = fopen (name, "wb");
	if (!cls.demofile)
	{
		Com_Printf ("ERROR: couldn't open.\n");
		return;
	}
	cls.demorecording = true;

	// don't start saving messages until a non-delta compressed message is received
	cls.demowaiting = true;

	//
	// write out messages to hold the startup information
	//
	SZ_Init (&buf, buf_data, sizeof(buf_data));

	// send the serverdata
	MSG_WriteByte (&buf, svc_serverdata);
	MSG_WriteLong (&buf, PROTOCOL_VERSION);
	MSG_WriteLong (&buf, 0x10000 + cl.servercount);
	MSG_WriteByte (&buf, 1);	// demos are always attract loops
	MSG_WriteString (&buf, cl.gamedir);
	MSG_WriteShort (&buf, cl.playernum);

	MSG_WriteString (&buf, cl.configstrings[CS_NAME]);

	// configstrings
	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
	{
		if (cl.configstrings[i][0])
		{
			if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize)
			{	// write it out
				len = LittleLong (buf.cursize);
				fwrite (&len, 4, 1, cls.demofile);
				fwrite (buf.data, buf.cursize, 1, cls.demofile);
				buf.cursize = 0;
			}

			MSG_WriteByte (&buf, svc_configstring);
			MSG_WriteShort (&buf, i);
			MSG_WriteString (&buf, cl.configstrings[i]);
		}

	}

	// baselines
	memset (&nullstate, 0, sizeof(nullstate));
	for (i=0; i<MAX_EDICTS ; i++)
	{
		ent = &cl_entities[i].baseline;
		if (!ent->modelindex)
			continue;

		if (buf.cursize + 64 > buf.maxsize)
		{	// write it out
			len = LittleLong (buf.cursize);
			fwrite (&len, 4, 1, cls.demofile);
			fwrite (buf.data, buf.cursize, 1, cls.demofile);
			buf.cursize = 0;
		}

		MSG_WriteByte (&buf, svc_spawnbaseline);		
		MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true);
	}

	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, "precache\n");

	// write it to the demo file

	len = LittleLong (buf.cursize);
	fwrite (&len, 4, 1, cls.demofile);
	fwrite (buf.data, buf.cursize, 1, cls.demofile);

	// the rest of the demo file will be individual frames
}
__cdecl void SV_WriteSnapshotToClient(client_t* client, msg_t* msg){

    snapshotInfo_t snapInfo;
    int lastframe;
    int from_num_entities;
    int newindex, oldindex, newnum, oldnum;
    clientState_ts *newcs, *oldcs;
    entityState_t *newent, *oldent;
    clientSnapshot_t *frame, *oldframe;
    int i;
    int snapFlags;
    int var_x, from_first_entity, from_num_clients, from_first_client;

    snapInfo.clnum = client - svsHeader.clients;
    snapInfo.cl = (void*)client;
    snapInfo.var_01 = 0;
    snapInfo.var_02 = 0;
    snapInfo.var_03 = 0;

    frame = &client->frames[client->netchan.outgoingSequence & PACKET_MASK];
    frame->var_03 = svsHeader.time;

    if(client->deltaMessage <= 0 ||  client->state != CS_ACTIVE) {
        oldframe = NULL;
        lastframe = 0;
        var_x = 0;

    } else if(client->netchan.outgoingSequence - client->deltaMessage >= PACKET_BACKUP - 3) {
        Com_DPrintf("%s: Delta request from out of date packet.\n", client->name);
        oldframe = NULL;
        lastframe = 0;
        var_x = 0;

    } else if(client->demoDeltaFrameCount <= 0 && client->demorecording){

        oldframe = NULL;
        lastframe = 0;
        var_x = 0;
        client->demowaiting = qfalse;
        Com_DPrintf("Force a nondelta frame for %s for demo recording\n", client->name);

        if(client->demoMaxDeltaFrames < 1024)
        {
            client->demoMaxDeltaFrames <<= 1;
        }
        client->demoDeltaFrameCount = client->demoMaxDeltaFrames;


    } else {
        oldframe = &client->frames[client->deltaMessage & PACKET_MASK];
        lastframe = client->netchan.outgoingSequence - client->deltaMessage;
        var_x = oldframe->var_03;
        client->demoDeltaFrameCount--;

        if(oldframe->first_entity <  svsHeader.nextSnapshotEntities - svsHeader.numSnapshotEntities) {
            Com_PrintWarning("%s: Delta request from out of date entities - delta against entity %i, oldest is %i, current is %i.  Their old snapshot had %i entities in it\n",
                            client->name, oldframe->first_entity, svs.nextSnapshotEntities - svs.numSnapshotEntities, svs.nextSnapshotEntities, oldframe->num_entities );
            oldframe = NULL;
            lastframe = 0;
            var_x = 0;

        } else if(oldframe->first_client <  svsHeader.nextSnapshotClients - svsHeader.numSnapshotClients) {

            Com_PrintWarning("%s: Delta request from out of date clients - delta against client %i, oldest is %i, current is %i.  Their old snapshot had %i clients in it\n", 
                            client->name, oldframe->first_client, svs.nextSnapshotClients - svs.numSnapshotClients, svs.nextSnapshotClients, oldframe->num_clients);
            oldframe = NULL;
            lastframe = 0;
            var_x = 0;
        }
    }


    MSG_WriteByte(msg, svc_snapshot);
    MSG_WriteLong(msg, svsHeader.time);
    MSG_WriteByte(msg, lastframe);
    snapInfo.var_01 = var_x;

    snapFlags = svsHeader.snapFlagServerBit;

    if(client->rateDelayed){
	snapFlags |= 1;
    }

    if(client->state == CS_ACTIVE) {

	client->unksnapshotvar = 1;

    } else {
	if(client->state != CS_ZOMBIE){
		client->unksnapshotvar = 0;
	}
    }

    if(!client->unksnapshotvar){
	snapFlags |= 2;
    }

    MSG_WriteByte(msg, snapFlags);

    if(oldframe) {
		MSG_WriteDeltaPlayerstate( &snapInfo, msg, svsHeader.time, &oldframe->ps, &frame->ps);
		from_num_entities = oldframe->num_entities;
		from_first_entity = oldframe->first_entity;
		from_num_clients = oldframe->num_clients;
		from_first_client = oldframe->first_client;
    } else {
	        MSG_WriteDeltaPlayerstate( &snapInfo, msg, svsHeader.time, 0, &frame->ps);
		from_num_entities = 0;
		from_first_entity = 0;
		from_num_clients = 0;
		from_first_client = 0;
    }

    MSG_ClearLastReferencedEntity(msg);


    newindex = 0;
    oldindex = 0;

//    Com_Printf("\nDelta client: %i:\n", snapInfo.clnum);


    while ( newindex < frame->num_entities || oldindex < from_num_entities){
	if ( newindex >= frame->num_entities ) {
		newnum = 9999;
		newent = NULL;
	} else {
		newent = &svsHeader.snapshotEntities[( frame->first_entity + newindex ) % svsHeader.numSnapshotEntities];
		newnum = newent->number;
	}

	if ( oldindex >= from_num_entities ) {
		oldnum = 9999;
		oldent = NULL;
	} else {
		oldent = &svsHeader.snapshotEntities[( from_first_entity + oldindex ) % svsHeader.numSnapshotEntities];
		oldnum = oldent->number;
	}

	if ( newnum == oldnum ) {
		// delta update from old position
		// because the force parm is qfalse, this will not result
		// in any bytes being emited if the entity has not changed at all
//		if(newent->number < 64 || oldent->number < 64)
//			Com_Printf("   Delta Update Entity - New delta: %i, %x  Old delta: %i, %x\n", newent->number, newent, oldent->number, oldent);
		MSG_WriteDeltaEntity( &snapInfo, msg, svsHeader.time, oldent, newent, qfalse );
		oldindex++;
		newindex++;
		continue;
	}

	if ( newnum < oldnum ) {
		// this is a new entity, send it from the baseline
		snapInfo.var_02 = 1;
//		if(newent->number < 64)
//			Com_Printf("   Delta Add Entity: %i, %x\n", newent->number, newent);
		MSG_WriteDeltaEntity( &snapInfo, msg, svsHeader.time, &svsHeader.svEntities[newnum].baseline, newent, qtrue );
		snapInfo.var_02 = 0;
		newindex++;
		continue;
	}

	if ( newnum > oldnum ) {
		// the old entity isn't present in the new message
//		if(oldent->number < 64)
//			Com_Printf("   Delta Remove Entity: %i, %x\n", oldent->number, oldent);
		MSG_WriteDeltaEntity( &snapInfo, msg, svsHeader.time, oldent, NULL, qtrue );
		oldindex++;
		continue;
	}
    }


    MSG_WriteEntityIndex(&snapInfo, msg, ( MAX_GENTITIES - 1 ), GENTITYNUM_BITS);
    MSG_ClearLastReferencedEntity(msg);

    newindex = 0;
    oldindex = 0;

    while(newindex < frame->num_clients || oldindex < from_num_clients){
	if(newindex >= frame->num_clients){
		newnum = 9999;
		newcs = NULL;
	}else{

		newcs = &svsHeader.snapshotClients[(frame->first_client + newindex) % svsHeader.numSnapshotClients];
		newnum = newcs->number;
	}

	if(oldindex >= from_num_clients){
		oldnum = 9999;
		oldcs = NULL;
	}else{

		oldcs = &svsHeader.snapshotClients[(from_first_client + oldindex) % svsHeader.numSnapshotClients];
		oldnum = oldcs->number;
	}

	if ( newnum == oldnum ) {
		// delta update from old position
		// because the force parm is qfalse, this will not result
		// in any bytes being emited if the entity has not changed at all
		MSG_WriteDeltaClient( &snapInfo, msg, svsHeader.time, oldcs, newcs, qfalse );
		oldindex++;
		newindex++;
		continue;
	}

	if ( newnum < oldnum ) {
		MSG_WriteDeltaClient( &snapInfo, msg, svsHeader.time, NULL, newcs, qtrue );
		newindex++;
		continue;
	}

	if ( newnum > oldnum ) {
		MSG_WriteDeltaClient( &snapInfo, msg, svsHeader.time, oldcs, NULL, qtrue );
		oldindex++;
		continue;
	}
    }

    MSG_WriteBit0(msg);

    if(sv_padPackets->integer){
	for( i=0 ; i < sv_padPackets->integer ; i++){
		MSG_WriteByte( msg, 0); //svc_nop
	}
    }
}
Exemple #23
0
/*
 * Writes a delta update of an entity_state_t list to the message.
 */
void
SV_EmitPacketEntities ( client_frame_t *from, client_frame_t *to, sizebuf_t *msg )
{
	entity_state_t  *oldent, *newent;
	int oldindex, newindex;
	int oldnum, newnum;
	int from_num_entities;
	int bits;

	MSG_WriteByte( msg, svc_packetentities );

	if ( !from )
	{
		from_num_entities = 0;
	}
	else
	{
		from_num_entities = from->num_entities;
	}

	newindex = 0;
	oldindex = 0;
	newent = NULL;
	oldent = NULL;

	while ( newindex < to->num_entities || oldindex < from_num_entities )
	{
		if ( msg->cursize > MAX_MSGLEN - 150 )
		{
			break;
		}

		if ( newindex >= to->num_entities )
		{
			newnum = 9999;
		}
		else
		{
			newent = &svs.client_entities [ ( to->first_entity + newindex ) % svs.num_client_entities ];
			newnum = newent->number;
		}

		if ( oldindex >= from_num_entities )
		{
			oldnum = 9999;
		}
		else
		{
			oldent = &svs.client_entities [ ( from->first_entity + oldindex ) % svs.num_client_entities ];
			oldnum = oldent->number;
		}

		if ( newnum == oldnum )
		{
			/* delta update from old position
			   because the force parm is false, this will not result
			   in any bytes being emited if the entity has not changed at all
			   note that players are always 'newentities', this updates their oldorigin always
			   and prevents warping */
			MSG_WriteDeltaEntity( oldent, newent, msg, false, newent->number <= maxclients->value );
			oldindex++;
			newindex++;
			continue;
		}

		if ( newnum < oldnum )
		{
			/* this is a new entity, send it from the baseline */
			MSG_WriteDeltaEntity( &sv.baselines [ newnum ], newent, msg, true, true );
			newindex++;
			continue;
		}

		if ( newnum > oldnum )
		{
			/* the old entity isn't present in the new message */
			bits = U_REMOVE;

			if ( oldnum >= 256 )
			{
				bits |= U_NUMBER16 | U_MOREBITS1;
			}

			MSG_WriteByte( msg, bits & 255 );

			if ( bits & 0x0000ff00 )
			{
				MSG_WriteByte( msg, ( bits >> 8 ) & 255 );
			}

			if ( bits & U_NUMBER16 )
			{
				MSG_WriteShort( msg, oldnum );
			}
			else
			{
				MSG_WriteByte( msg, oldnum );
			}

			oldindex++;
			continue;
		}
Exemple #24
0
/*
=============
SV_EmitPacketEntities

Writes a delta update of an entity_state_t list to the message->
=============
*/
void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg )
{
	entity_state_t	*oldent, *newent;
	int		oldindex, newindex;
	int		oldnum, newnum;
	int		from_num_entities;
	client_frame_t	*from;

	// this is the frame that we are going to delta update from
	if( cl->delta_sequence != -1 )
	{
		from = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK];
		from_num_entities = from->num_entities;

		// the snapshot's entities may still have rolled off the buffer, though
		if( from->first_entity <= svs.next_client_entities - svs.num_client_entities )
		{
			MsgDev( D_WARN, "%s: delta request from out of date entities.\n", cl->name );

			from = NULL;
			from_num_entities = 0;

			BF_WriteByte( msg, svc_packetentities );
			BF_WriteWord( msg, to->num_entities );
		}
		else
		{
			BF_WriteByte( msg, svc_deltapacketentities );
			BF_WriteWord( msg, to->num_entities );
			BF_WriteByte( msg, cl->delta_sequence );
		}
	}
	else
	{
		from = NULL;
		from_num_entities = 0;

		BF_WriteByte( msg, svc_packetentities );
		BF_WriteWord( msg, to->num_entities );
	}

	newent = NULL;
	oldent = NULL;
	newindex = 0;
	oldindex = 0;

	while( newindex < to->num_entities || oldindex < from_num_entities )
	{
		if( newindex >= to->num_entities )
		{
			newnum = MAX_ENTNUMBER;
		}
		else
		{
			newent = &svs.packet_entities[(to->first_entity+newindex)%svs.num_client_entities];
			newnum = newent->number;
		}

		if( oldindex >= from_num_entities )
		{
			oldnum = MAX_ENTNUMBER;
		}
		else
		{
			oldent = &svs.packet_entities[(from->first_entity+oldindex)%svs.num_client_entities];
			oldnum = oldent->number;
		}

		if( newnum == oldnum )
		{	
			// delta update from old position
			// because the force parm is false, this will not result
			// in any bytes being emited if the entity has not changed at all
			MSG_WriteDeltaEntity( oldent, newent, msg, false, SV_IsPlayerIndex( newent->number ), sv.time );
			oldindex++;
			newindex++;
			continue;
		}

		if( newnum < oldnum )
		{	
			// this is a new entity, send it from the baseline
			MSG_WriteDeltaEntity( &svs.baselines[newnum], newent, msg, true, SV_IsPlayerIndex( newent->number ), sv.time );
			newindex++;
			continue;
		}

		if( newnum > oldnum )
		{	
			qboolean	force;

			if( EDICT_NUM( oldent->number )->free )
				force = true;	// entity completely removed from server
			else force = false;		// just removed from delta-message 

			// remove from message
			MSG_WriteDeltaEntity( oldent, NULL, msg, force, false, sv.time );
			oldindex++;
			continue;
		}
	}

	BF_WriteWord( msg, 0 ); // end of packetentities
}
Exemple #25
0
/*
* SNAP_BeginDemoRecording
*/
void SNAP_BeginDemoRecording( int demofile, unsigned int spawncount, unsigned int snapFrameTime, 
	const char *sv_name, unsigned int sv_bitflags, purelist_t *purelist, char *configstrings, 
	entity_state_t *baselines )
{
	unsigned int i;
	msg_t msg;
	uint8_t msg_buffer[MAX_MSGLEN];
	purelist_t *purefile;
	entity_state_t nullstate;
	entity_state_t *base;

	MSG_Init( &msg, msg_buffer, sizeof( msg_buffer ) );

	SNAP_DemoMetaDataMessage( &msg, "", 0 );

	SNAP_RecordDemoMetaDataMessage( demofile, &msg );

	// serverdata message
	MSG_WriteByte( &msg, svc_serverdata );
	MSG_WriteLong( &msg, APP_DEMO_PROTOCOL_VERSION );
	MSG_WriteLong( &msg, spawncount );
	MSG_WriteShort( &msg, (unsigned short)snapFrameTime );
	MSG_WriteString( &msg, FS_BaseGameDirectory() );
	MSG_WriteString( &msg, FS_GameDirectory() );
	MSG_WriteShort( &msg, -1 ); // playernum
	MSG_WriteString( &msg, sv_name ); // level name
	MSG_WriteByte( &msg, sv_bitflags & ~SV_BITFLAGS_HTTP ); // sv_bitflags

	// pure files
	i = Com_CountPureListFiles( purelist );
	if( i > (short)0x7fff )
		Com_Error( ERR_DROP, "Error: Too many pure files." );

	MSG_WriteShort( &msg, i );

	purefile = purelist;
	while( purefile )
	{
		MSG_WriteString( &msg, purefile->filename );
		MSG_WriteLong( &msg, purefile->checksum );
		purefile = purefile->next;

		DEMO_SAFEWRITE( demofile, &msg, false );
	}

	// config strings
	for( i = 0; i < MAX_CONFIGSTRINGS; i++ )
	{
		const char *configstring = configstrings + i * MAX_CONFIGSTRING_CHARS;
		if( configstring[0] )
		{
			MSG_WriteByte( &msg, svc_servercs );
			MSG_WriteString( &msg, va( "cs %i \"%s\"", i, configstring ) );

			DEMO_SAFEWRITE( demofile, &msg, false );
		}
	}

	// baselines
	memset( &nullstate, 0, sizeof( nullstate ) );

	for( i = 0; i < MAX_EDICTS; i++ )
	{
		base = &baselines[i];
		if( base->modelindex || base->sound || base->effects )
		{
			MSG_WriteByte( &msg, svc_spawnbaseline );
			MSG_WriteDeltaEntity( &nullstate, base, &msg, true, true );

			DEMO_SAFEWRITE( demofile, &msg, false );
		}
	}

	// client expects the server data to be in a separate packet
	DEMO_SAFEWRITE( demofile, &msg, true );

	MSG_WriteByte( &msg, svc_servercs );
	MSG_WriteString( &msg, "precache" );

	DEMO_SAFEWRITE( demofile, &msg, true );
}