Exemple #1
0
/*
==================
SV_FinalMessage

Used by SV_Shutdown to send a final message to all
connected clients before the server goes down.  The messages are sent immediately,
not just stuck on the outgoing message list, because the server is going
to totally exit after returning from this function.
==================
*/
void SV_FinalMessage( char *message, qboolean reconnect )
{
	sv_client_t	*cl;
	byte		msg_buf[1024];
	sizebuf_t		msg;
	int		i;
	
	BF_Init( &msg, "FinalMessage", msg_buf, sizeof( msg_buf ));
	BF_WriteByte( &msg, svc_print );
	BF_WriteByte( &msg, PRINT_HIGH );
	BF_WriteString( &msg, va( "%s\n", message ));

	if( reconnect )
	{
		BF_WriteByte( &msg, svc_changing );

		if( sv.loadgame || sv_maxclients->integer > 1 || sv.changelevel )
			BF_WriteOneBit( &msg, 1 ); // changelevel
		else BF_WriteOneBit( &msg, 0 );
	}
	else
	{
		BF_WriteByte( &msg, svc_disconnect );
	}

	// send it twice
	// stagger the packets to crutch operating system limited buffers
	for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
		if( cl->state >= cs_connected && !cl->fakeclient )
			Netchan_Transmit( &cl->netchan, BF_GetNumBytesWritten( &msg ), BF_GetData( &msg ));

	for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
		if( cl->state >= cs_connected && !cl->fakeclient )
			Netchan_Transmit( &cl->netchan, BF_GetNumBytesWritten( &msg ), BF_GetData( &msg ));
}
Exemple #2
0
/*
=============
SV_EmitPings

=============
*/
void SV_EmitPings( sizebuf_t *msg )
{
	sv_client_t	*cl;
	int		packet_loss;
	int		i, ping;

	BF_WriteByte( msg, svc_updatepings );

	for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if( cl->state != cs_spawned )
			continue;

		SV_GetPlayerStats( cl, &ping, &packet_loss );

		// there are 25 bits for each client
		BF_WriteOneBit( msg, 1 );
		BF_WriteUBitLong( msg, i, MAX_CLIENT_BITS );
		BF_WriteUBitLong( msg, ping, 12 );
		BF_WriteUBitLong( msg, packet_loss, 7 );
	}

	// end marker
	BF_WriteOneBit( msg, 0 );
}
Exemple #3
0
/*
==================
MSG_WriteWeaponData

Writes current client data only for local client
Other clients can grab the client state from entity_state_t
==================
*/
void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, float timebase, int index )
{
	delta_t		*pField;
	delta_info_t	*dt;
	int		i, startBit;
	int		numChanges = 0;

	dt = Delta_FindStruct( "weapon_data_t" );
	if( !dt || !dt->bInitialized )
	{
		Host_Error( "MSG_WriteWeaponData: delta not initialized!\n" );
	}

	pField = dt->pFields;
	ASSERT( pField );

	// activate fields and call custom encode func
	Delta_CustomEncode( dt, from, to );

	startBit = msg->iCurBit;

	BF_WriteOneBit( msg, 1 );
	BF_WriteUBitLong( msg, index, MAX_WEAPON_BITS );
               
	// process fields
	for( i = 0; i < dt->numFields; i++, pField++ )
	{
		if( Delta_WriteField( msg, pField, from, to, timebase ))
			numChanges++;
	}

	// if we have no changes - kill the message
	if( !numChanges ) BF_SeekToBit( msg, startBit );
}
Exemple #4
0
void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t *pField )
{
	int		nameIndex;
	delta_info_t	*dt;
	
	ASSERT( pField );

	if( !pField->name || !*pField->name )
		return;	// not initialized ?

	dt = Delta_FindStructByIndex( tableIndex );
	ASSERT( dt && dt->bInitialized );

	nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name );
	ASSERT( nameIndex >= 0 && nameIndex < dt->maxFields );

	BF_WriteByte( msg, svc_deltatable );
	BF_WriteUBitLong( msg, tableIndex, 4 );		// assume we support 16 network tables
	BF_WriteUBitLong( msg, nameIndex, 8 );		// 255 fields by struct should be enough
	BF_WriteUBitLong( msg, pField->flags, 10 );	// flags are indicated various input types
	BF_WriteUBitLong( msg, pField->bits - 1, 5 );	// max received value is 32 (32 bit)

	// multipliers is null-compressed
	if( pField->multiplier != 1.0f )
	{
		BF_WriteOneBit( msg, 1 );
		BF_WriteFloat( msg, pField->multiplier );
	}
	else BF_WriteOneBit( msg, 0 );

	if( pField->post_multiplier != 1.0f )
	{
		BF_WriteOneBit( msg, 1 );
		BF_WriteFloat( msg, pField->post_multiplier );
	}
	else BF_WriteOneBit( msg, 0 );
}
Exemple #5
0
/*
==================
SV_WriteClientdataToMessage

==================
*/
void SV_WriteClientdataToMessage( sv_client_t *cl, sizebuf_t *msg )
{
	clientdata_t	nullcd;
	clientdata_t	*from_cd, *to_cd;
	weapon_data_t	nullwd;
	weapon_data_t	*from_wd, *to_wd;
	client_frame_t	*frame;
	edict_t		*clent;
	int		i;

	Q_memset( &nullcd, 0, sizeof( nullcd ));

	clent = cl->edict;
	frame = &cl->frames[cl->netchan.outgoing_sequence & SV_UPDATE_MASK];

	frame->senttime = host.realtime;
	frame->raw_ping = -1.0f;
	frame->latency = -1.0f;

	if( cl->chokecount != 0 )
	{
		BF_WriteByte( msg, svc_chokecount );
		BF_WriteByte( msg, cl->chokecount );
		cl->chokecount = 0;
	}

	// update client fixangle
	switch( clent->v.fixangle )
	{
	case 1:
		BF_WriteByte( msg, svc_setangle );
		BF_WriteBitAngle( msg, clent->v.angles[0], 16 );
		BF_WriteBitAngle( msg, clent->v.angles[1], 16 );
		BF_WriteBitAngle( msg, clent->v.angles[2], 16 );
		clent->v.effects |= EF_NOINTERP;
		break;
	case 2:
		BF_WriteByte( msg, svc_addangle );
		BF_WriteBitAngle( msg, clent->v.avelocity[1], 16 );
		clent->v.avelocity[1] = 0.0f;
		break;
	}

	clent->v.fixangle = 0; // reset fixangle
	clent->v.pushmsec = 0; // reset net framenum
	Q_memset( &frame->clientdata, 0, sizeof( frame->clientdata ));

	// update clientdata_t

	svgame.dllFuncs.pfnUpdateClientData( clent, cl->local_weapons, &frame->clientdata );

	BF_WriteByte( msg, svc_clientdata );
	if( cl->hltv_proxy ) return;	// don't send more nothing

	if( cl->delta_sequence == -1 ) from_cd = &nullcd;
	else from_cd = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK].clientdata;
	to_cd = &frame->clientdata;

	if( cl->delta_sequence == -1 )
	{
		BF_WriteOneBit( msg, 0 );	// no delta-compression
	}
	else
	{
		BF_WriteOneBit( msg, 1 );	// we are delta-ing from
		BF_WriteByte( msg, cl->delta_sequence );
	}

	// write clientdata_t
	MSG_WriteClientData( msg, from_cd, to_cd, sv.time );

	if( cl->local_weapons && svgame.dllFuncs.pfnGetWeaponData( clent, frame->weapondata ))
	{
		Q_memset( &nullwd, 0, sizeof( nullwd ));

		for( i = 0; i < 64; i++ )
		{
			if( cl->delta_sequence == -1 ) from_wd = &nullwd;
			else from_wd = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK].weapondata[i];
			to_wd = &frame->weapondata[i];

			MSG_WriteWeaponData( msg, from_wd, to_wd, sv.time, i );
		}
	}

	// end marker
	BF_WriteOneBit( msg, 0 );
}
Exemple #6
0
/*
=============
SV_EmitEvents

=============
*/
static void SV_EmitEvents( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg )
{
	event_state_t	*es;
	event_info_t	*info;
	entity_state_t	*state;
	event_args_t	nullargs;
	int		ev_count = 0;
	int		count, ent_index;
	int		i, j, ev;

	Q_memset( &nullargs, 0, sizeof( nullargs ));

	es = &cl->events;

	// count events
	for( ev = 0; ev < MAX_EVENT_QUEUE; ev++ )
	{
		if( es->ei[ev].index ) ev_count++;
	}

	// nothing to send
	if( !ev_count ) return; // nothing to send

	if( ev_count >= 31 ) ev_count = 31;

	for( i = 0; i < MAX_EVENT_QUEUE; i++ )
	{
		info = &es->ei[i];
		if( info->index == 0 )
			continue;

		ent_index = info->entity_index;

		for( j = 0; j < to->num_entities; j++ )
		{
			state = &svs.packet_entities[(to->first_entity+j)%svs.num_client_entities];
			if( state->number == ent_index )
				break;
		}

		if( j >= to->num_entities )
		{
			// couldn't find
			info->packet_index = to->num_entities;
			info->args.entindex = ent_index;
		}
		else
		{
			info->packet_index = j;
			info->args.ducking = 0;

			if(!( info->args.flags & FEVENT_ORIGIN ))
				VectorClear( info->args.origin );

			if(!( info->args.flags & FEVENT_ANGLES ))
				VectorClear( info->args.angles );

			VectorClear( info->args.velocity );
		}
	}

	BF_WriteByte( msg, svc_event );	// create message
	BF_WriteUBitLong( msg, ev_count, 5 );	// up to MAX_EVENT_QUEUE events

	for( count = i = 0; i < MAX_EVENT_QUEUE; i++ )
	{
		info = &es->ei[i];

		if( info->index == 0 )
		{
			info->packet_index = -1;
			info->entity_index = -1;
			continue;
		}

		// only send if there's room
		if( count < ev_count )
		{
			BF_WriteUBitLong( msg, info->index, MAX_EVENT_BITS ); // 1024 events

			if( info->packet_index == -1 )
			{
				BF_WriteOneBit( msg, 0 );
			}
			else
			{
				BF_WriteOneBit( msg, 1 );
				BF_WriteUBitLong( msg, info->packet_index, MAX_ENTITY_BITS );

				if( !Q_memcmp( &nullargs, &info->args, sizeof( event_args_t )))
				{
					BF_WriteOneBit( msg, 0 );
				}
				else
				{
					BF_WriteOneBit( msg, 1 );
					MSG_WriteDeltaEvent( msg, &nullargs, &info->args );
				}
			}

			if( info->fire_time )
			{
				BF_WriteOneBit( msg, 1 );
				BF_WriteWord( msg, Q_rint( info->fire_time * 100.0f ));
			}
			else BF_WriteOneBit( msg, 0 );
		}

		info->index = 0;
		info->packet_index = -1;
		info->entity_index = -1;
		count++;
	}
}
Exemple #7
0
/*
==================
MSG_WriteDeltaEntity

Writes part of a packetentities message, including the entity number.
Can delta from either a baseline or a previous packet_entity
If to is NULL, a remove entity update will be sent
If force is not set, then nothing at all will be generated if the entity is
identical, under the assumption that the in-order delta code will catch it.
==================
*/
void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean player, float timebase ) 
{
	delta_info_t	*dt = NULL;
	delta_t		*pField;
	int		i, startBit;
	int		numChanges = 0;

	if( to == NULL )
	{
		int	fRemoveType;

		if( from == NULL ) return;

		// a NULL to is a delta remove message
		BF_WriteWord( msg, from->number );

		// fRemoveType:
		// 0 - keep alive, has delta-update
		// 1 - remove from delta message (but keep states)
		// 2 - completely remove from server
		if( force ) fRemoveType = 2;
		else fRemoveType = 1;

		BF_WriteUBitLong( msg, fRemoveType, 2 );
		return;
	}

	startBit = msg->iCurBit;

	if( to->number < 0 || to->number >= GI->max_edicts )
	{
		MsgDev( D_ERROR, "MSG_WriteDeltaEntity: Bad entity number: %i\n", to->number );
		return;
	}

	BF_WriteWord( msg, to->number );
	BF_WriteUBitLong( msg, 0, 2 ); // alive

	if( to->entityType != from->entityType )
	{
		BF_WriteOneBit( msg, 1 );
		BF_WriteUBitLong( msg, to->entityType, 2 );
	}
	else BF_WriteOneBit( msg, 0 ); 

	if( to->entityType == ENTITY_NORMAL )
	{
		if( player )
		{
			dt = Delta_FindStruct( "entity_state_player_t" );
		}
		else
		{
			dt = Delta_FindStruct( "entity_state_t" );
		}
	}
	else if( to->entityType == ENTITY_BEAM )
	{
		dt = Delta_FindStruct( "custom_entity_state_t" );
	}

	ASSERT( dt && dt->bInitialized );
		
	pField = dt->pFields;
	ASSERT( pField );

	// activate fields and call custom encode func
	Delta_CustomEncode( dt, from, to );

	// process fields
	for( i = 0; i < dt->numFields; i++, pField++ )
	{
		if( Delta_WriteField( msg, pField, from, to, timebase ))
			numChanges++;
	}

	// if we have no changes - kill the message
	if( !numChanges && !force ) BF_SeekToBit( msg, startBit );
}
Exemple #8
0
/*
=====================
Delta_WriteField

write fields by offsets
assume from and to is valid
=====================
*/
qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase )
{
	qboolean		bSigned = ( pField->flags & DT_SIGNED ) ? true : false;
	float		flValue, flAngle, flTime;
	uint		iValue;
	const char	*pStr;

	if( Delta_CompareField( pField, from, to, timebase ))
	{
		BF_WriteOneBit( msg, 0 );	// unchanged
		return false;
	}

	BF_WriteOneBit( msg, 1 );	// changed

	if( pField->flags & DT_BYTE )
	{
		iValue = *(byte *)((byte *)to + pField->offset );
		iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits );
		if ( pField->multiplier != 1.0f ) iValue *= pField->multiplier;
		BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
	}
	else if( pField->flags & DT_SHORT )
	{
		iValue = *(word *)((byte *)to + pField->offset );
		iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits );
		if ( pField->multiplier != 1.0f ) iValue *= pField->multiplier;
		BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
	}
	else if( pField->flags & DT_INTEGER )
	{
		iValue = *(uint *)((byte *)to + pField->offset );
		iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits );
		if ( pField->multiplier != 1.0f ) iValue *= pField->multiplier;
		BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
	}
	else if( pField->flags & DT_FLOAT )
	{
		#ifdef __arm__
		memcpy(&flValue,(byte *)to + pField->offset, sizeof(float) );
		#else
		flValue = *(float *)((byte *)to + pField->offset );
		#endif
		iValue = (int)(flValue * pField->multiplier);
		BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
	}
	else if( pField->flags & DT_ANGLE )
	{
		#ifdef __arm__
		memcpy(&flAngle,(byte *)to + pField->offset, sizeof(float) );
		#else
		flAngle = *(float *)((byte *)to + pField->offset );
		#endif

		// NOTE: never applies multipliers to angle because
		// result may be wrong on client-side
		BF_WriteBitAngle( msg, flAngle, pField->bits );
	}
	else if( pField->flags & DT_TIMEWINDOW_8 )
	{
		#ifdef __arm__
		memcpy(&flValue,(byte *)to + pField->offset, sizeof(float) );
		#else
		flValue = *(float *)((byte *)to + pField->offset );
		#endif
		flTime = (timebase * 100.0f) - (flValue * 100.0f);
		#if 1
		iValue = (uint)fabs( flTime );
		#else
		iValue = (uint)fabs( flTime );
		if (flTime<0.0f) {
			iValue |= 0x80000000;
		}
		#endif

		BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
	}
	else if( pField->flags & DT_TIMEWINDOW_BIG )
	{
		#ifdef __arm__
		memcpy(&flValue,(byte *)to + pField->offset, sizeof(float) );
		#else
		flValue = *(float *)((byte *)to + pField->offset );
		#endif
		flTime = (timebase * pField->multiplier) - (flValue * pField->multiplier);
		#if 1
		iValue = (uint)fabs( flTime );
		#else
		iValue = (uint)fabs( flTime );
		if (flTime<0.0f) {
			iValue |= 0x80000000;
		}
		#endif

		BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
	}
	else if( pField->flags & DT_STRING )
	{
		pStr = (char *)((byte *)to + pField->offset );
		BF_WriteString( msg, pStr );
	}
	return true;
}