Beispiel #1
0
void Delta_ParseTableField( sizebuf_t *msg )
{
	int		tableIndex, nameIndex;
	float		mul = 1.0f, post_mul = 1.0f;
	int		flags, bits;
	const char	*pName;
	delta_info_t	*dt;

	tableIndex = BF_ReadUBitLong( msg, 4 );
	dt = Delta_FindStructByIndex( tableIndex );

	if( !dt )
		Host_Error( "Delta_ParseTableField: not initialized" );
	nameIndex = BF_ReadUBitLong( msg, 8 );	// read field name index		
	if( !( nameIndex >= 0 && nameIndex < dt->maxFields ) )
		Host_Error( "Delta_ParseTableField: wrong nameIndex" );
	pName = dt->pInfo[nameIndex].name;
	flags = BF_ReadUBitLong( msg, 10 );
	bits = BF_ReadUBitLong( msg, 5 ) + 1;

	// read the multipliers
	if( BF_ReadOneBit( msg ))
		mul = BF_ReadFloat( msg );

	if( BF_ReadOneBit( msg ))
		post_mul = BF_ReadFloat( msg );

	// delta encoders it's already initialized on this machine (local game)
	if( delta_init ) return;

	// add field to table
	Delta_AddField( dt->pName, pName, flags, bits, mul, post_mul );
}
Beispiel #2
0
/*
================
CL_UpdateUserinfo

collect userinfo from all players
================
*/
void CL_UpdateUserinfo( sizebuf_t *msg )
{
	int		slot;
	qboolean		active;
	player_info_t	*player;

	slot = BF_ReadUBitLong( msg, MAX_CLIENT_BITS );

	if( slot >= MAX_CLIENTS )
		Host_Error( "CL_ParseServerMessage: svc_updateuserinfo > MAX_CLIENTS\n" );

	player = &cl.players[slot];
	active = BF_ReadOneBit( msg ) ? true : false;

	if( active )
	{
		Q_strncpy( player->userinfo, BF_ReadString( msg ), sizeof( player->userinfo ));
		Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name ));
		Q_strncpy( player->model, Info_ValueForKey( player->userinfo, "model" ), sizeof( player->model ));
		cl.playermodels[slot] = 0;
		player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
		player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));

		if( slot == cl.playernum ) Q_memcpy( &menu.playerinfo, player, sizeof( player_info_t ));
	}
	else Q_memset( player, 0, sizeof( *player ));
}
Beispiel #3
0
/*
=============
CL_ParseReliableEvent

=============
*/
void CL_ParseReliableEvent( sizebuf_t *msg )
{
	int		event_index;
	event_args_t	nullargs, args;
	float		delay = 0.0f;
	cl_entity_t	*pEnt;

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

	event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS );

	if( BF_ReadOneBit( msg ))
		delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f);

	// reliable events not use delta-compression just null-compression
	MSG_ReadDeltaEvent( msg, &nullargs, &args );

	if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL )
	{
		if( VectorIsNull( args.origin ))
			VectorCopy( pEnt->curstate.origin, args.origin );
		if( VectorIsNull( args.angles ))
			VectorCopy( pEnt->curstate.angles, args.angles );
		if( VectorIsNull( args.velocity ))
			VectorCopy( pEnt->curstate.velocity, args.velocity );
	}

	CL_QueueEvent( FEV_RELIABLE|FEV_SERVER, event_index, delay, &args );
}
Beispiel #4
0
/*
================
CL_UpdateUserPings

collect pings and packet lossage from clients
================
*/
void CL_UpdateUserPings( sizebuf_t *msg )
{
	int		i, slot;
	player_info_t	*player;
	
	for( i = 0; i < MAX_CLIENTS; i++ )
	{
		if( !BF_ReadOneBit( msg )) break; // end of message

		slot = BF_ReadUBitLong( msg, MAX_CLIENT_BITS );

		if( slot >= MAX_CLIENTS )
			Host_Error( "CL_ParseServerMessage: svc_updatepings > MAX_CLIENTS\n" );

		player = &cl.players[slot];
		player->ping = BF_ReadUBitLong( msg, 12 );
		player->packet_loss = BF_ReadUBitLong( msg, 7 );
	}
}
Beispiel #5
0
/*
===================
CL_ParseClientData
===================
*/
void CL_ParseClientData( sizebuf_t *msg )
{
	int		i, j;
	clientdata_t	*from_cd, *to_cd;
	weapon_data_t	*from_wd, *to_wd;
	weapon_data_t	nullwd[32];
	clientdata_t	nullcd;
	frame_t		*frame;
	int		idx;

	// this is the frame update that this message corresponds to
	i = cls.netchan.incoming_sequence;

	// did we drop some frames?
	if( i > cl.last_incoming_sequence + 1 )
	{
		// mark as dropped
		for( j = cl.last_incoming_sequence + 1; j < i; j++ )
		{
			if( cl.frames[j & CL_UPDATE_MASK].receivedtime >= 0.0 )
			{
				cl.frames[j & CL_UPDATE_MASK].receivedtime = -1;
				cl.frames[j & CL_UPDATE_MASK].latency = 0;
			}
		}
	}

	cl.parsecount = i;					// ack'd incoming messages.  
	cl.parsecountmod = cl.parsecount & CL_UPDATE_MASK;	// index into window.     
	frame = &cl.frames[cl.parsecountmod];			// frame at index.

	frame->time = cl.mtime[0];				// mark network received time
	frame->receivedtime = host.realtime;			// time now that we are parsing.  

	if( cl.last_command_ack != -1 )
	{
		int last_predicted;
		entity_state_t * ps;
		entity_state_t * pps;
		clientdata_t * pcd;
		clientdata_t * ppcd;
		weapon_data_t * wd;
		weapon_data_t * pwd;

		last_predicted = ( cl.last_incoming_sequence + (
							   cls.netchan.incoming_acknowledged - cl.last_command_ack)) & CL_UPDATE_MASK;

		pps = &cl.predict[last_predicted].playerstate;
		ppcd = &cl.predict[last_predicted].client;
		pwd = cl.predict[last_predicted].weapondata;

		ps = &frame->playerstate[cl.playernum];
		pcd = &frame->local.client;
		wd = frame->local.weapondata;

		clgame.dllFuncs.pfnTxferPredictionData( ps, pps, pcd, ppcd, wd, pwd );
	}

	// do this after all packets read for this frame?
	cl.last_command_ack = cls.netchan.incoming_acknowledged;
	cl.last_incoming_sequence = cls.netchan.incoming_sequence;

	if( hltv->integer ) return;	// clientdata for spectators ends here
	
	to_cd = &frame->local.client;
	to_wd = frame->local.weapondata;

	// clear to old value before delta parsing
	if( !BF_ReadOneBit( msg ))
	{
		Q_memset( &nullcd, 0, sizeof( nullcd ));
		Q_memset( nullwd, 0, sizeof( nullwd ));
		from_cd = &nullcd;
		from_wd = nullwd;
	}
	else
	{
		int	delta_sequence = BF_ReadByte( msg );

		from_cd = &cl.frames[delta_sequence & CL_UPDATE_MASK].local.client;
		from_wd = cl.frames[delta_sequence & CL_UPDATE_MASK].local.weapondata;
	}

	MSG_ReadClientData( msg, from_cd, to_cd, cl.mtime[0] );

	for( i = 0; i < MAX_WEAPONS; i++ )
	{
		// check for end of weapondata (and clientdata_t message)
		if( !BF_ReadOneBit( msg )) break;

		// read the weapon idx
		idx = BF_ReadUBitLong( msg, MAX_WEAPON_BITS );

		MSG_ReadWeaponData( msg, &from_wd[idx], &to_wd[idx], cl.mtime[0] );
	}
}
Beispiel #6
0
/*
==================
CL_ParseServerData
==================
*/
void CL_ParseServerData( sizebuf_t *msg )
{
	string	gamefolder;
	qboolean	background;
	int	i;

	MsgDev( D_NOTE, "Serverdata packet received.\n" );

	cls.demowaiting = false;	// server is changed
	clgame.load_sequence++;	// now all hud sprites are invalid

	// wipe the client_t struct
	if( !cls.changelevel && !cls.changedemo )
		CL_ClearState ();
	cls.state = ca_connected;

	// parse protocol version number
	i = BF_ReadLong( msg );
	cls.serverProtocol = i;

	if( i != PROTOCOL_VERSION )
		Host_Error( "Server uses invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION );

	cl.servercount = BF_ReadLong( msg );
	cl.checksum = BF_ReadLong( msg );
	cl.playernum = BF_ReadByte( msg );
	cl.maxclients = BF_ReadByte( msg );
	clgame.maxEntities = BF_ReadWord( msg );
	clgame.maxEntities = bound( 600, clgame.maxEntities, 4096 );
	Q_strncpy( clgame.mapname, BF_ReadString( msg ), MAX_STRING );
	Q_strncpy( clgame.maptitle, BF_ReadString( msg ), MAX_STRING );
	background = BF_ReadOneBit( msg );
	Q_strncpy( gamefolder, BF_ReadString( msg ), MAX_STRING );
	host.features = (uint)BF_ReadLong( msg );

	if( cl.maxclients > 1 && host.developer < 1 )
		host.developer++;

	// set the background state
	if( cls.demoplayback && ( cls.demonum != -1 ))
	{
		// re-init mouse
		host.mouse_visible = false;
		cl.background = true;
	}
	else cl.background = background;

	if( cl.background )	// tell the game parts about background state
		Cvar_FullSet( "cl_background", "1", CVAR_READ_ONLY );
	else Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY );

	if( !cls.changelevel ) 
	{
		// continue playing if we are changing level
		S_StopBackgroundTrack ();
	}
#if 0
	// NOTE: this is not tested as well. Use with precaution
	CL_ChangeGame( gamefolder, false );
#endif
	if( !cls.changedemo )
		UI_SetActiveMenu( cl.background );

	cl.refdef.viewentity = cl.playernum + 1; // always keep viewent an actual

	menu.globals->maxClients = cl.maxclients;
	Q_strncpy( menu.globals->maptitle, clgame.maptitle, sizeof( menu.globals->maptitle ));

	if( cl.maxclients > 1 && r_decals->value > mp_decals->value )
		Cvar_SetFloat( "r_decals", mp_decals->value );

	if( !cls.changelevel && !cls.changedemo )
		CL_InitEdicts (); // re-arrange edicts

	// get splash name
	if( cls.demoplayback && ( cls.demonum != -1 ))
		Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", cls.demoname, glState.wideScreen ? "16x9" : "4x3" ));
	else Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", clgame.mapname, glState.wideScreen ? "16x9" : "4x3" ));
	Cvar_SetFloat( "scr_loading", 0.0f ); // reset progress bar

	if(( cl_allow_levelshots->integer && !cls.changelevel ) || cl.background )
	{
		if( !FS_FileExists( va( "%s.bmp", cl_levelshot_name->string ), true )) 
			Cvar_Set( "cl_levelshot_name", "*black" ); // render a black screen
		cls.scrshot_request = scrshot_plaque; // request levelshot even if exist (check filetime)
	}

	if( scr_dark->integer )
	{
		screenfade_t		*sf = &clgame.fade;
		client_textmessage_t	*title;

		title = CL_TextMessageGet( "GAMETITLE" );

		if( title )
		{
			// get settings from titles.txt
			sf->fadeEnd = title->holdtime + title->fadeout;
			sf->fadeReset = title->fadeout;
		}
		else sf->fadeEnd = sf->fadeReset = 4.0f;
	
		sf->fadeFlags = FFADE_IN;
		sf->fader = sf->fadeg = sf->fadeb = 0;
		sf->fadealpha = 255;
		sf->fadeSpeed = (float)sf->fadealpha / sf->fadeReset;
		sf->fadeReset += cl.time;
		sf->fadeEnd += sf->fadeReset;
		
		Cvar_SetFloat( "v_dark", 0.0f );
	}

	// need to prep refresh at next oportunity
	cl.video_prepped = false;
	cl.audio_prepped = false;

	Q_memset( &clgame.movevars, 0, sizeof( clgame.movevars ));
	Q_memset( &clgame.oldmovevars, 0, sizeof( clgame.oldmovevars ));
}
Beispiel #7
0
/*
=====================
CL_ParseServerMessage
=====================
*/
void CL_ParseServerMessage( sizebuf_t *msg )
{
	char	*s;
	int	i, j, cmd;
	int	param1, param2;
	int	bufStart;

	cls_message_debug.parsing = true;		// begin parsing
	starting_count = BF_GetNumBytesRead( msg );	// updates each frame
	
	// parse the message
	while( 1 )
	{
		if( BF_CheckOverflow( msg ))
		{
			Host_Error( "CL_ParseServerMessage: overflow!\n" );
			return;
		}

		// mark start position
		bufStart = BF_GetNumBytesRead( msg );

		// end of message
		if( BF_GetNumBitsLeft( msg ) < 8 )
			break;		

		cmd = BF_ReadByte( msg );

		// record command for debugging spew on parse problem
		CL_Parse_RecordCommand( cmd, bufStart );

		// other commands
		switch( cmd )
		{
		case svc_bad:
			Host_Error( "svc_bad\n" );
			break;
		case svc_nop:
			// this does nothing
			break;
		case svc_disconnect:
			MsgDev( D_INFO, "Disconnected from server\n" );
			CL_Drop ();
			Host_AbortCurrentFrame ();
			break;
		case svc_changing:
			if( BF_ReadOneBit( msg ))
			{
				cls.changelevel = true;
				S_StopAllSounds();

				if( cls.demoplayback )
				{
					SCR_BeginLoadingPlaque( cl.background );
					cls.changedemo = true;
				}
			}
			else MsgDev( D_INFO, "Server disconnected, reconnecting\n" );

			CL_ClearState ();
			CL_InitEdicts (); // re-arrange edicts

			if( cls.demoplayback )
			{
				cl.background = (cls.demonum != -1) ? true : false;
				cls.state = ca_connected;
			}
			else cls.state = ca_connecting;
			cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately
			break;
		case svc_setview:
			cl.refdef.viewentity = BF_ReadWord( msg );
			break;
		case svc_sound:
			CL_ParseSoundPacket( msg, false );
			break;
		case svc_time:
			// shuffle timestamps
			cl.mtime[1] = cl.mtime[0];
			cl.mtime[0] = BF_ReadFloat( msg );			
			break;
		case svc_print:
			i = BF_ReadByte( msg );
			MsgDev( D_INFO, "^6%s", BF_ReadString( msg ));
			if( i == PRINT_CHAT ) S_StartLocalSound( "common/menu2.wav", VOL_NORM, false );
			break;
		case svc_stufftext:
			CL_ParseStuffText( msg );
			break;
		case svc_lightstyle:
			CL_ParseLightStyle( msg );
			break;
		case svc_setangle:
			CL_ParseSetAngle( msg );
			break;
		case svc_serverdata:
			Cbuf_Execute(); // make sure any stuffed commands are done
			CL_ParseServerData( msg );
			break;
		case svc_addangle:
			CL_ParseAddAngle( msg );
			break;
		case svc_clientdata:
			CL_ParseClientData( msg );
			break;
		case svc_packetentities:
			CL_ParsePacketEntities( msg, false );
			break;
		case svc_deltapacketentities:
			CL_ParsePacketEntities( msg, true );
			break;
		case svc_updatepings:
			CL_UpdateUserPings( msg );
			break;
		case svc_usermessage:
			CL_RegisterUserMessage( msg );
			break;
		case svc_particle:
			CL_ParseParticles( msg );
			break;
		case svc_restoresound:
			CL_ParseRestoreSoundPacket( msg );
			break;
		case svc_spawnstatic:
			CL_ParseStaticEntity( msg );
			break;
		case svc_ambientsound:
			CL_ParseSoundPacket( msg, true );
			break;
		case svc_crosshairangle:
			CL_ParseCrosshairAngle( msg );
			break;
		case svc_spawnbaseline:
			CL_ParseBaseline( msg );
			break;
		case svc_temp_entity:
			CL_ParseTempEntity( msg );
			break;
		case svc_setpause:
			cl.refdef.paused = ( BF_ReadOneBit( msg ) != 0 );
			break;
		case svc_deltamovevars:
			CL_ParseMovevars( msg );
			break;
		case svc_customization:
			CL_ParseCustomization( msg );
			break;
		case svc_centerprint:
			CL_CenterPrint( BF_ReadString( msg ), 0.25f );
			break;
		case svc_event:
			CL_ParseEvent( msg );
			break;
		case svc_event_reliable:
			CL_ParseReliableEvent( msg );
			break;
		case svc_updateuserinfo:
			CL_UpdateUserinfo( msg );
			break;
		case svc_intermission:
			cl.refdef.intermission = true;
			break;
		case svc_modelindex:
			CL_PrecacheModel( msg );
			break;
		case svc_soundindex:
			CL_PrecacheSound( msg );
			break;
		case svc_soundfade:
			CL_ParseSoundFade( msg );
			break;
		case svc_cdtrack:
			param1 = BF_ReadByte( msg );
			param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum
			param2 = BF_ReadByte( msg );
			param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum
			S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0 );
			break;
		case svc_serverinfo:
			CL_ServerInfo( msg );
			break;
		case svc_eventindex:
			CL_PrecacheEvent( msg );
			break;
		case svc_deltatable:
			Delta_ParseTableField( msg );
			break;
		case svc_weaponanim:
			param1 = BF_ReadByte( msg );	// iAnim
			param2 = BF_ReadByte( msg );	// body
			CL_WeaponAnim( param1, param2 );
			break;
		case svc_bspdecal:
			CL_ParseStaticDecal( msg );
			break;
		case svc_roomtype:
			param1 = BF_ReadShort( msg );
			Cvar_SetFloat( "room_type", param1 );
			break;
		case svc_chokecount:
			i = BF_ReadByte( msg );
			j = cls.netchan.incoming_acknowledged - 1;
			for( ; i > 0 && j > cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP; j-- )
			{
				if( cl.frames[j & CL_UPDATE_MASK].receivedtime != -3.0 )
				{
					cl.frames[j & CL_UPDATE_MASK].receivedtime = -2.0;
					i--;
				}
			}
			break;
		case svc_resourcelist:
			CL_ParseResourceList( msg );
			break;
		case svc_director:
			CL_ParseDirector( msg );
			break;
		case svc_studiodecal:
			CL_ParseStudioDecal( msg );
			break;
		case svc_querycvarvalue:
			CL_ParseCvarValue( msg );
			break;
		case svc_querycvarvalue2:
			CL_ParseCvarValue2( msg );
			break;
		default:
			CL_ParseUserMessage( msg, cmd );
			break;
		}
	}

	cls_message_debug.parsing = false;	// done

	// we don't know if it is ok to save a demo message until
	// after we have parsed the frame
	if( !cls.demoplayback )
	{
		if( cls.demorecording && !cls.demowaiting )
		{
			CL_WriteDemoMessage( false, starting_count, msg );
		}
		else if( cls.state != ca_active )
		{
			CL_WriteDemoMessage( true, starting_count, msg );
		}
	}
}
Beispiel #8
0
/*
=============
CL_ParseEvent

=============
*/
void CL_ParseEvent( sizebuf_t *msg )
{
	int		event_index;
	int		i, num_events;
	int		packet_ent;
	event_args_t	nullargs, args;
	qboolean		has_update;
	entity_state_t	*state;
	cl_entity_t	*pEnt;
	float		delay;

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

	num_events = BF_ReadUBitLong( msg, 5 );

	// parse events queue
	for( i = 0 ; i < num_events; i++ )
	{
		event_index = BF_ReadUBitLong( msg, MAX_EVENT_BITS );
		Q_memset( &args, 0, sizeof( args ));
		has_update = false;

		if( BF_ReadOneBit( msg ))
		{
			packet_ent = BF_ReadUBitLong( msg, MAX_ENTITY_BITS );

			if( BF_ReadOneBit( msg ))
			{
				MSG_ReadDeltaEvent( msg, &nullargs, &args );
				has_update = true;
			}
		}
		else packet_ent = -1;

		if( packet_ent != -1 )
			state = &cls.packet_entities[(cl.frame.first_entity+packet_ent)%cls.num_client_entities];
		else state = NULL;

		// it's a client. Override some params
		if( args.entindex >= 1 && args.entindex <= cl.maxclients )
		{
			if(( args.entindex - 1 ) == cl.playernum )
			{
				if( state && !CL_IsPredicted( ))
				{
					// restore viewangles from angles
					args.angles[PITCH] = -state->angles[PITCH] * 3;
					args.angles[YAW] = state->angles[YAW];
					args.angles[ROLL] = 0; // no roll
				}
				else
				{
					// get the predicted angles
					VectorCopy( cl.refdef.cl_viewangles, args.angles );
				}

				VectorCopy( cl.frame.local.client.origin, args.origin );
				VectorCopy( cl.frame.local.client.velocity, args.velocity );
			}
			else if( state )
			{
				// restore viewangles from angles
				args.angles[PITCH] = -state->angles[PITCH] * 3;
				args.angles[YAW] = state->angles[YAW];
				args.angles[ROLL] = 0; // no roll

				// if we restore origin and velocity everytime, why don't do it here also?
				if( VectorIsNull( args.origin ))
					VectorCopy( state->origin, args.origin );
				if( VectorIsNull( args.velocity ))
					VectorCopy( state->velocity, args.velocity );
			}
		}
		else if( state )
		{
			if( VectorIsNull( args.origin ))
				VectorCopy( state->origin, args.origin );
			if( VectorIsNull( args.angles ))
				VectorCopy( state->angles, args.angles );
			if( VectorIsNull( args.velocity ))
				VectorCopy( state->velocity, args.velocity );
		}
		else if(( pEnt = CL_GetEntityByIndex( args.entindex )) != NULL )
		{
			if( VectorIsNull( args.origin ))
				VectorCopy( pEnt->curstate.origin, args.origin );
			if( VectorIsNull( args.angles ))
				VectorCopy( pEnt->curstate.angles, args.angles );
			if( VectorIsNull( args.velocity ))
				VectorCopy( pEnt->curstate.velocity, args.velocity );
		}

		if( BF_ReadOneBit( msg ))
			delay = (float)BF_ReadWord( msg ) * (1.0f / 100.0f);
		else delay = 0.0f;

		// g-cont. should we need find the event with same index?
		CL_QueueEvent( 0, event_index, delay, &args );
	}
}
Beispiel #9
0
/*
==================
MSG_ReadDeltaEntity

The entity number has already been read from the message, which
is how the from state is identified.
                             
If the delta removes the entity, entity_state_t->number will be set to MAX_EDICTS
Can go from either a baseline or a previous packet_entity
==================
*/
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, qboolean player, float timebase )
{
	delta_info_t	*dt = NULL;
	delta_t		*pField;
	int		i, fRemoveType;
#ifndef XASH_DEDICATED
	if( number < 0 || number >= clgame.maxEntities )
	{
		// broken packet, try to skip it
		MsgDev( D_ERROR, "MSG_ReadDeltaEntity: bad delta entity number: %i\n", number );
		return false;
	}

	*to = *from;
	to->number = number;
	fRemoveType = BF_ReadUBitLong( msg, 2 );

	if( fRemoveType )
	{
		// check for a remove
		Q_memset( to, 0, sizeof( *to ));

		if( fRemoveType & 1 )
		{
			// removed from delta-message
			return false;
                    }

		if( fRemoveType & 2 )
		{	
			// entity was removed from server
			to->number = -1;
			return false;
		}

		MsgDev( D_ERROR, "MSG_ReadDeltaEntity: unknown update type %i\n", fRemoveType );
		return false;
	}

	if( BF_ReadOneBit( msg ))
		to->entityType = BF_ReadUBitLong( msg, 2 );


	if( to->entityType == ENTITY_BEAM )
	{
		dt = Delta_FindStruct( "custom_entity_state_t" );
	}
	else //  ENTITY_NORMAL or other (try predict type)
	{
		/* Omit connection drop on wromg data from server.
		 * I know that it is very dirty,
		 * but i don't know how to do it better.*/
		if( to->entityType != ENTITY_NORMAL )
			MsgDev( D_NOTE, "MSG_ReadDeltaEntity: broken delta: entityType = %d\n", to->entityType );
		if( player )
		{
			dt = Delta_FindStruct( "entity_state_player_t" );
		}
		else
		{
			dt = Delta_FindStruct( "entity_state_t" );
		}
	}

	if( !(dt && dt->bInitialized) ) // Broken  delta?
	{
		MsgDev( D_ERROR, "MSG_ReadDeltaEntity: broken delta\n");
		return true;
	}
	pField = dt->pFields;
	ASSERT( pField );

	// process fields
	for( i = 0; i < dt->numFields; i++, pField++ )
	{
		Delta_ReadField( msg, pField, from, to, timebase );
	}
#endif
	// message parsed
	return true;
}
Beispiel #10
0
/*
=====================
Delta_ReadField

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

	ASSERT( pField->multiplier != 0.0f );

	if( pField->flags & DT_BYTE )
	{
		if( bChanged )
		{
			iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
			if ( pField->multiplier != 1.0f ) iValue /= pField->multiplier;
		}
		else
		{
			iValue = *(byte *)((byte *)from + pField->offset );
		}
		*(byte *)((byte *)to + pField->offset ) = iValue;
	}
	else if( pField->flags & DT_SHORT )
	{
		if( bChanged )
		{
			iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
			if ( pField->multiplier != 1.0f ) iValue /= pField->multiplier;
		}
		else
		{
			iValue = *(word *)((byte *)from + pField->offset );
		}
		*(word *)((byte *)to + pField->offset ) = iValue;
	}
	else if( pField->flags & DT_INTEGER )
	{
		if( bChanged )
		{
			iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
			if ( pField->multiplier != 1.0f ) iValue /= pField->multiplier;
		}
		else
		{
			iValue = *(uint *)((byte *)from + pField->offset );
		}
		*(uint *)((byte *)to + pField->offset ) = iValue;
	}
	else if( pField->flags & DT_FLOAT )
	{
		if( bChanged )
		{
			iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
			flValue = (int)iValue * ( 1.0f / pField->multiplier );
			flValue = flValue * pField->post_multiplier;
		}
		else
		{
			#ifdef __arm__
			memcpy(&flValue, (byte *)from + pField->offset, sizeof(float) );
			#else
			flValue = *(float *)((byte *)from + pField->offset );
			#endif
		}
		#ifdef __arm__
		memcpy((byte *)to + pField->offset, &flValue, sizeof(float));
		#else
		*(float *)((byte *)to + pField->offset ) = flValue;
		#endif
	}
	else if( pField->flags & DT_ANGLE )
	{
		if( bChanged )
		{
			flAngle = BF_ReadBitAngle( msg, pField->bits );
		}
		else
		{
			#ifdef __arm__
			memcpy(&flAngle, (byte *)from + pField->offset, sizeof(float) );
			#else
			flAngle = *(float *)((byte *)from + pField->offset );
			#endif
		}
		#ifdef __arm__
		memcpy((byte *)to + pField->offset, &flAngle, sizeof(float));
		#else
		*(float *)((byte *)to + pField->offset ) = flAngle;
		#endif
	}
	else if( pField->flags & DT_TIMEWINDOW_8 )
	{
		if( bChanged )
		{
			iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
			flValue = (float)((int)(iValue * 0.01f ));
			flTime = timebase + flValue;
		}
		else
		{
			#ifdef __arm__
			memcpy(&flTime, (byte *)from + pField->offset, sizeof(float) );
			#else
			flTime = *(float *)((byte *)from + pField->offset );
			#endif
		}
		#ifdef __arm__
		memcpy((byte *)to + pField->offset, &flTime, sizeof(float));
		#else
		*(float *)((byte *)to + pField->offset ) = flTime;
		#endif
	}
	else if( pField->flags & DT_TIMEWINDOW_BIG )
	{
		if( bChanged )
		{
			iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
			flValue = (float)((int)iValue) * ( 1.0f / pField->multiplier );
			flTime = timebase + flValue;
		}
		else
		{
			#ifdef __arm__
			memcpy(&flTime, (byte *)from + pField->offset, sizeof(float) );
			#else
			flTime = *(float *)((byte *)from + pField->offset );
			#endif
		}
		#ifdef __arm__
		memcpy((byte *)to + pField->offset, &flTime, sizeof(float));
		#else
		*(float *)((byte *)to + pField->offset ) = flTime;
		#endif
	}
	else if( pField->flags & DT_STRING )
	{
		if( bChanged )
		{
			pStr = BF_ReadString( msg );
		}
		else
		{
			pStr = (char *)((byte *)from + pField->offset );
		}

		pOut = (char *)((byte *)to + pField->offset );
		Q_strncpy( pOut, pStr, pField->size );
	}
	return bChanged;
}
Beispiel #11
0
/*
==================
MSG_ReadDeltaEntity

The entity number has already been read from the message, which
is how the from state is identified.

If the delta removes the entity, entity_state_t->number will be set to MAX_EDICTS
Can go from either a baseline or a previous packet_entity
==================
*/
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, qboolean player, float timebase )
{
	delta_info_t	*dt = NULL;
	delta_t		*pField;
	int		i, fRemoveType;

#ifndef _DEDICATED
	if( number < 0 || number >= clgame.maxEntities )
		Host_Error( "MSG_ReadDeltaEntity: bad delta entity number: %i\n", number );
#endif

	*to = *from;
	to->number = number;
	fRemoveType = BF_ReadUBitLong( msg, 2 );

	if( fRemoveType )
	{
		// check for a remove
		Q_memset( to, 0, sizeof( *to ));

		if( fRemoveType & 1 )
		{
			// removed from delta-message
			return false;
                    }

		if( fRemoveType & 2 )
		{
			// entity was removed from server
			to->number = -1;
			return false;
		}

		Host_Error( "MSG_ReadDeltaEntity: unknown update type %i\n", fRemoveType );
	}

	if( BF_ReadOneBit( msg ))
		to->entityType = BF_ReadUBitLong( msg, 2 );

	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 );

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

	// message parsed
	return true;
}