Exemple #1
0
/*
==============
CL_ParseScreenShake

Set screen shake
==============
*/
void CL_ParseScreenShake( sizebuf_t *msg )
{
	clgame.shake.amplitude = (float)(word)BF_ReadShort( msg ) * (1.0f / (float)(1U << 12));
	clgame.shake.duration = (float)(word)BF_ReadShort( msg ) * (1.0f / (float)(1U << 12));
	clgame.shake.frequency = (float)(word)BF_ReadShort( msg ) * (1.0f / (float)(1U << 8));
	clgame.shake.time = cl.time + max( clgame.shake.duration, 0.01f );
	clgame.shake.next_shake = 0.0f; // apply immediately
}
Exemple #2
0
/*
==============
CL_ParseStudioDecal

Studio Decal message. Used by engine in case
we need save\restore decals
==============
*/
void CL_ParseStudioDecal( sizebuf_t *msg )
{
	modelstate_t	state;
	vec3_t		start, pos;
	int		decalIndex, entityIndex;
	int		modelIndex = 0;
	int		flags;

	pos[0] = BF_ReadCoord( msg );
	pos[1] = BF_ReadCoord( msg );
	pos[2] = BF_ReadCoord( msg );
	start[0] = BF_ReadCoord( msg );
	start[1] = BF_ReadCoord( msg );
	start[2] = BF_ReadCoord( msg );
	decalIndex = BF_ReadShort( msg );
	entityIndex = BF_ReadShort( msg );
	flags = BF_ReadByte( msg );

	state.sequence = BF_ReadShort( msg );
	state.frame = BF_ReadShort( msg );
	state.blending[0] = BF_ReadByte( msg );
	state.blending[1] = BF_ReadByte( msg );
	state.controller[0] = BF_ReadByte( msg );
	state.controller[1] = BF_ReadByte( msg );
	state.controller[2] = BF_ReadByte( msg );
	state.controller[3] = BF_ReadByte( msg );

	if( cls.state == ca_connected )
	{
		// this message came on restore.
		// read modelindex in case client models are not linked with entities
		// because first client frame has not yet received
		modelIndex = BF_ReadShort( msg );
	}

	if( clgame.drawFuncs.R_StudioDecalShoot )
	{
		int decalTexture = CL_DecalIndex( decalIndex );
		cl_entity_t *ent = CL_GetEntityByIndex( entityIndex );

		if( ent && !ent->model && modelIndex != 0 )
			ent->model = Mod_Handle( modelIndex );

		clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state );
	}
}
Exemple #3
0
/*
==============
CL_ParseScreenFade

Set screen fade
==============
*/
void CL_ParseScreenFade( sizebuf_t *msg )
{
	float		duration, holdTime;
	screenfade_t	*sf = &clgame.fade;

	duration = (float)(word)BF_ReadShort( msg ) * (1.0f / (float)(1U << 12));
	holdTime = (float)(word)BF_ReadShort( msg ) * (1.0f / (float)(1U << 12));
	sf->fadeFlags = BF_ReadShort( msg );

	sf->fader = BF_ReadByte( msg );
	sf->fadeg = BF_ReadByte( msg );
	sf->fadeb = BF_ReadByte( msg );
	sf->fadealpha = BF_ReadByte( msg );
	sf->fadeSpeed = 0.0f;
	sf->fadeEnd = duration;
	sf->fadeReset = holdTime;

	// calc fade speed
	if( duration > 0 )
	{
		if( sf->fadeFlags & FFADE_OUT )
		{
			if( sf->fadeEnd )
			{
				sf->fadeSpeed = -(float)sf->fadealpha / sf->fadeEnd;
			}

			sf->fadeEnd += cl.time;
			sf->fadeReset += sf->fadeEnd;
		}
		else
		{
			if( sf->fadeEnd )
			{
				sf->fadeSpeed = (float)sf->fadealpha / sf->fadeEnd;
			}

			sf->fadeReset += cl.time;
			sf->fadeEnd += sf->fadeReset;
		}
	}
}
Exemple #4
0
/*
==============
CL_ParseStudioDecal

Studio Decal message. Used by engine in case
we need save\restore decals
==============
*/
void CL_ParseStudioDecal( sizebuf_t *msg )
{
	modelstate_t	state;
	vec3_t		start, pos;
	int		decalIndex, entityIndex;
	int		modelIndex = 0;
	int		flags;

	BF_ReadVec3Coord( msg, pos );
	BF_ReadVec3Coord( msg, start );
	decalIndex = BF_ReadWord( msg );
	entityIndex = BF_ReadWord( msg );
	flags = BF_ReadByte( msg );

	state.sequence = BF_ReadShort( msg );
	state.frame = BF_ReadShort( msg );
	state.blending[0] = BF_ReadByte( msg );
	state.blending[1] = BF_ReadByte( msg );
	state.controller[0] = BF_ReadByte( msg );
	state.controller[1] = BF_ReadByte( msg );
	state.controller[2] = BF_ReadByte( msg );
	state.controller[3] = BF_ReadByte( msg );
	modelIndex = BF_ReadWord( msg );
	state.body = BF_ReadByte( msg );
	state.skin = BF_ReadByte( msg );

	if( clgame.drawFuncs.R_StudioDecalShoot != NULL )
	{
		int decalTexture = CL_DecalIndex( decalIndex );
		cl_entity_t *ent = CL_GetEntityByIndex( entityIndex );

		if( ent && !ent->model && modelIndex != 0 )
			ent->model = Mod_Handle( modelIndex );

		clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state );
	}
}
Exemple #5
0
/*
==================
CL_ParseStaticDecal

==================
*/
void CL_ParseStaticDecal( sizebuf_t *msg )
{
	vec3_t	origin;
	int	decalIndex, entityIndex, modelIndex;
	int	flags;

	BF_ReadBitVec3Coord( msg, origin );
	decalIndex = BF_ReadWord( msg );
	entityIndex = BF_ReadShort( msg );

	if( entityIndex > 0 )
		modelIndex = BF_ReadWord( msg );
	else modelIndex = 0;
	flags = BF_ReadByte( msg );

	CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags );
}
Exemple #6
0
/*
==================
CL_ParseStaticDecal

==================
*/
void CL_ParseStaticDecal( sizebuf_t *msg )
{
	vec3_t		origin;
	int		decalIndex, entityIndex, modelIndex;
	cl_entity_t	*ent = NULL;
	float		scale;
	int		flags;

	BF_ReadVec3Coord( msg, origin );
	decalIndex = BF_ReadWord( msg );
	entityIndex = BF_ReadShort( msg );

	if( entityIndex > 0 )
		modelIndex = BF_ReadWord( msg );
	else modelIndex = 0;
	flags = BF_ReadByte( msg );
	scale = (float)BF_ReadWord( msg ) / 4096.0f;

	CL_FireCustomDecal( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags, scale );
}
Exemple #7
0
/*
==================
CL_ParseStaticEntity

static client entity
==================
*/
void CL_ParseStaticEntity( sizebuf_t *msg )
{
	entity_state_t	state;
	cl_entity_t	*ent;
	int		i;

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

	state.modelindex = BF_ReadShort( msg );
	state.sequence = BF_ReadByte( msg );
	state.frame = BF_ReadByte( msg );
	state.colormap = BF_ReadWord( msg );
	state.skin = BF_ReadByte( msg );

	for( i = 0; i < 3; i++ )
	{
		state.origin[i] = BF_ReadCoord( msg );
		state.angles[i] = BF_ReadBitAngle( msg, 16 );
	}

	state.rendermode = BF_ReadByte( msg );

	if( state.rendermode != kRenderNormal )
	{
		state.renderamt = BF_ReadByte( msg );
		state.rendercolor.r = BF_ReadByte( msg );
		state.rendercolor.g = BF_ReadByte( msg );
		state.rendercolor.b = BF_ReadByte( msg );
		state.renderfx = BF_ReadByte( msg );
	}

	i = clgame.numStatics;
	if( i >= MAX_STATIC_ENTITIES )
	{
		MsgDev( D_ERROR, "CL_ParseStaticEntity: static entities limit exceeded!\n" );
		return;
	}

	ent = &clgame.static_entities[i];
	clgame.numStatics++;

	ent->index = 0; // ???
	ent->baseline = state;
	ent->curstate = state;
	ent->prevstate = state;

	// statics may be respawned in game e.g. for demo recording
	if( cls.state == ca_connected )
		ent->trivial_accept = INVALID_HANDLE;

	// setup the new static entity
	CL_UpdateEntityFields( ent );

	if( Mod_GetType( state.modelindex ) == mod_studio )
	{
		CL_UpdateStudioVars( ent, &state, true );

		// animate studio model
		ent->curstate.animtime = cl.time;
		ent->curstate.framerate = 1.0f;
		ent->latched.prevframe = 0.0f;
	}

	R_AddEfrags( ent );	// add link
}
Exemple #8
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 );
		}
	}
}
Exemple #9
0
/*
=================
CL_ConnectionlessPacket

Responses to broadcasts, etc
=================
*/
void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
{
	char	*args;
	char	*c, buf[MAX_SYSPATH];
	int	len = sizeof( buf ), i = 0;
	netadr_t servadr;
	
	BF_Clear( msg );
	BF_ReadLong( msg ); // skip the -1

	args = BF_ReadStringLine( msg );

	Cmd_TokenizeString( args );
	c = Cmd_Argv( 0 );

	MsgDev( D_NOTE, "CL_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c );

	// server connection
	if( !Q_strcmp( c, "client_connect" ))
	{
		if( cls.state == ca_connected )
		{
			MsgDev( D_INFO, "Dup connect received. Ignored.\n");
			return;
		}

		Netchan_Setup( NS_CLIENT, &cls.netchan, from, net_qport->integer);
		BF_WriteByte( &cls.netchan.message, clc_stringcmd );
		BF_WriteString( &cls.netchan.message, "new" );
		cls.state = ca_connected;

		cl.validsequence = 0;		// haven't gotten a valid frame update yet
		cl.delta_sequence = -1;		// we'll request a full delta from the baseline
		cls.lastoutgoingcommand = -1;		// we don't have a backed up cmd history yet
		cls.nextcmdtime = host.realtime;	// we can send a cmd right away

		CL_StartupDemoHeader ();
	}
	else if( !Q_strcmp( c, "info" ))
	{
		// server responding to a status broadcast
		CL_ParseStatusMessage( from, msg );
	}
	else if( !Q_strcmp( c, "netinfo" ))
	{
		// server responding to a status broadcast
		CL_ParseNETInfoMessage( from, msg );
	}
	else if( !Q_strcmp( c, "cmd" ))
	{
		// remote command from gui front end
		if( !NET_IsLocalAddress( from ))
		{
			Msg( "Command packet from remote host. Ignored.\n" );
			return;
		}
#ifdef XASH_SDL
		SDL_RestoreWindow( host.hWnd );
#endif
		args = BF_ReadString( msg );
		Cbuf_AddText( args );
		Cbuf_AddText( "\n" );
	}
	else if( !Q_strcmp( c, "print" ))
	{
		// print command from somewhere
		Msg("remote: %s\n", BF_ReadString( msg ) );
	}
	else if( !Q_strcmp( c, "ping" ))
	{
		// ping from somewhere
		Netchan_OutOfBandPrint( NS_CLIENT, from, "ack" );
	}
	else if( !Q_strcmp( c, "challenge" ))
	{
		// challenge from the server we are connecting to
		cls.challenge = Q_atoi( Cmd_Argv( 1 ));
		CL_SendConnectPacket();
		return;
	}
	else if( !Q_strcmp( c, "echo" ))
	{
		// echo request from server
		Netchan_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv( 1 ));
	}
	else if( !Q_strcmp( c, "disconnect" ))
	{
		// a disconnect message from the server, which will happen if the server
		// dropped the connection but it is still getting packets from us
		CL_Disconnect();
		CL_ClearEdicts();
	}
	else if( !Q_strcmp( c, "f") )
	{
		// serverlist got from masterserver
		while( !msg->bOverflow )
		{
			servadr.type = NA_IP;
			// 4 bytes for IP
			BF_ReadBytes( msg, servadr.ip, sizeof( servadr.ip ));
			// 2 bytes for Port
			servadr.port = BF_ReadShort( msg );

			if( !servadr.port )
				break;

			MsgDev( D_INFO, "Found server: %s\n", NET_AdrToString( servadr ));

			NET_Config( true ); // allow remote

			Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
		}

		// execute at next frame preventing relation on fps
		Cbuf_AddText("menu_resetping\n");
	}
	else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
	{
		// user out of band message (must be handled in CL_ConnectionlessPacket)
		if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, (byte *)buf );
	}
	else MsgDev( D_ERROR, "Bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
}
Exemple #10
0
/*
=================
SV_ReadPackets
=================
*/
void SV_ReadPackets( void )
{
	sv_client_t	*cl;
	int		i, qport, curSize;

	while( NET_GetPacket( NS_SERVER, &net_from, net_message_buffer, &curSize ))
	{
		BF_Init( &net_message, "ClientPacket", net_message_buffer, curSize );

		// check for connectionless packet (0xffffffff) first
		if( BF_GetMaxBytes( &net_message ) >= 4 && *(int *)net_message.pData == -1 )
		{
			SV_ConnectionlessPacket( net_from, &net_message );
			continue;
		}

		// read the qport out of the message so we can fix up
		// stupid address translating routers
		BF_Clear( &net_message );
		BF_ReadLong( &net_message );	// sequence number
		BF_ReadLong( &net_message );	// sequence number
		qport = (int)BF_ReadShort( &net_message ) & 0xffff;

		// check for packets from connected clients
		for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
		{
			if( cl->state == cs_free || cl->fakeclient )
				continue;

			if( !NET_CompareBaseAdr( net_from, cl->netchan.remote_address ))
				continue;

			if( cl->netchan.qport != qport )
				continue;

			if( cl->netchan.remote_address.port != net_from.port )
			{
				MsgDev( D_INFO, "SV_ReadPackets: fixing up a translated port\n");
				cl->netchan.remote_address.port = net_from.port;
			}

			if( Netchan_Process( &cl->netchan, &net_message ))
			{	
				cl->send_message = true; // reply at end of frame

				// this is a valid, sequenced packet, so process it
				if( cl->state != cs_zombie )
				{
					cl->lastmessage = host.realtime; // don't timeout
					SV_ExecuteClientMessage( cl, &net_message );
					svgame.globals->frametime = host.frametime;
					svgame.globals->time = sv.time;
				}
			}

			// fragmentation/reassembly sending takes priority over all game messages, want this in the future?
			if( Netchan_IncomingReady( &cl->netchan ))
			{
				if( Netchan_CopyNormalFragments( &cl->netchan, &net_message ))
				{
					BF_Clear( &net_message );
					SV_ExecuteClientMessage( cl, &net_message );
				}

				if( Netchan_CopyFileFragments( &cl->netchan, &net_message ))
				{
					SV_ProcessFile( cl, cl->netchan.incomingfilename );
				}
			}
			break;
		}

		if( i != sv_maxclients->integer )
			continue;
	}
}