示例#1
0
void demoCutParseRMG(msg_t *msg, clientConnection_t *clcCut, clientActive_t *clCut) {
	int i;
	clcCut->rmgHeightMapSize = (unsigned short)MSG_ReadShort(msg);
	if (clcCut->rmgHeightMapSize == 0) {
		return;
	}
	z_stream zdata;
	int flatDataSize;
	unsigned char heightmap1[15000];
	// height map
	if (MSG_ReadBits(msg, 1)) {
		memset(&zdata, 0, sizeof(z_stream));
		inflateInit(&zdata/*, Z_SYNC_FLUSH*/);
		MSG_ReadData (msg, heightmap1, clcCut->rmgHeightMapSize);
		zdata.next_in = heightmap1;
		zdata.avail_in = clcCut->rmgHeightMapSize;
		zdata.next_out = (unsigned char*)clcCut->rmgHeightMap;
		zdata.avail_out = MAX_HEIGHTMAP_SIZE;
		inflate(&zdata,Z_SYNC_FLUSH);
		clcCut->rmgHeightMapSize = zdata.total_out;
		inflateEnd(&zdata);
	} else {
		MSG_ReadData(msg, (unsigned char*)clcCut->rmgHeightMap, clcCut->rmgHeightMapSize);
	}
	// Flatten map
	flatDataSize = MSG_ReadShort(msg);
	if (MSG_ReadBits(msg, 1)) {	
		// Read the flatten map
		memset(&zdata, 0, sizeof(z_stream));
		inflateInit(&zdata/*, Z_SYNC_FLUSH*/);
		MSG_ReadData ( msg, heightmap1, flatDataSize);
		zdata.next_in = heightmap1;
		zdata.avail_in = clcCut->rmgHeightMapSize;
		zdata.next_out = (unsigned char*)clcCut->rmgFlattenMap;
		zdata.avail_out = MAX_HEIGHTMAP_SIZE;
		inflate(&zdata, Z_SYNC_FLUSH);
		inflateEnd(&zdata);
	} else {
		MSG_ReadData(msg, (unsigned char*)clcCut->rmgFlattenMap, flatDataSize);
	}
	// Seed
	clcCut->rmgSeed = MSG_ReadLong(msg);
	// Automap symbols
	clcCut->rmgAutomapSymbolCount = (unsigned short)MSG_ReadShort(msg);
	for(i = 0; i < clcCut->rmgAutomapSymbolCount; i++) {
		clcCut->rmgAutomapSymbols[i].mType = (int)MSG_ReadByte(msg);
		clcCut->rmgAutomapSymbols[i].mSide = (int)MSG_ReadByte(msg);
		clcCut->rmgAutomapSymbols[i].mOrigin[0] = (float)MSG_ReadLong(msg);
		clcCut->rmgAutomapSymbols[i].mOrigin[1] = (float)MSG_ReadLong(msg);
	}
}
示例#2
0
文件: cl_parse.c 项目: Slipyx/r1q2
void CL_ParseZPacket (void)
{
#ifndef NO_ZLIB
	byte buff_in[MAX_MSGLEN];
	byte buff_out[0xFFFF];

	sizebuf_t sb, old;

	int16 compressed_len = (int16)MSG_ReadShort (&net_message);
	int16 uncompressed_len = (int16)MSG_ReadShort (&net_message);
	
	if (uncompressed_len <= 0)
		Com_Error (ERR_DROP, "CL_ParseZPacket: uncompressed_len <= 0");

	if (compressed_len <= 0)
		Com_Error (ERR_DROP, "CL_ParseZPacket: compressed_len <= 0");

	MSG_ReadData (&net_message, buff_in, compressed_len);

	SZ_Init (&sb, buff_out, uncompressed_len);
	sb.cursize = ZLibDecompress (buff_in, compressed_len, buff_out, uncompressed_len, -15);

	old = net_message;
	net_message = sb;
	CL_ParseServerMessage ();
	net_message = old;

	Com_DPrintf ("Got a ZPacket, %d->%d\n", uncompressed_len + 4, compressed_len);
#else
	Com_Error (ERR_DROP, "Receied a zPacket but no zlib in this binary");
#endif
}
示例#3
0
文件: save.c 项目: jdolan/q2pro
static int read_level_file(void)
{
    char    name[MAX_OSPATH];
    size_t  len, maxlen;
    int     index;

    len = Q_snprintf(name, MAX_QPATH, "save/" SAVE_CURRENT "/%s.sv2", sv.name);
    if (len >= MAX_QPATH)
        return -1;

    if (read_binary_file(name))
        return -1;

    if (MSG_ReadLong() != SAVE_MAGIC2)
        return -1;

    if (MSG_ReadLong() != SAVE_VERSION)
        return -1;

    // any error will drop from this point

    // the rest can't underflow
    msg_read.allowunderflow = qfalse;

    // read all configstrings
    while (1) {
        index = MSG_ReadShort();
        if (index == MAX_CONFIGSTRINGS)
            break;

        if (index < 0 || index > MAX_CONFIGSTRINGS)
            Com_Error(ERR_DROP, "Bad savegame configstring index");

        maxlen = CS_SIZE(index);
        len = MSG_ReadString(sv.configstrings[index], maxlen);
        if (len >= maxlen)
            Com_Error(ERR_DROP, "Savegame configstring too long");
    }

    len = MSG_ReadByte();
    if (len > MAX_MAP_PORTAL_BYTES)
        Com_Error(ERR_DROP, "Savegame portalbits too long");

    SV_ClearWorld();

    CM_SetPortalStates(&sv.cm, MSG_ReadData(len), len);

    // read game level
    len = Q_snprintf(name, MAX_OSPATH, "%s/save/" SAVE_CURRENT "/%s.sav",
                     fs_gamedir, sv.name);
    if (len >= MAX_OSPATH)
        Com_Error(ERR_DROP, "Savegame path too long");

    ge->ReadLevel(name);
    return 0;
}
示例#4
0
void CL_ParseZPacket (sizebuf_t *msg)
{
	byte buff_in[MAX_MSGLEN];
	byte buff_out[0xFFFF];
	sizebuf_t sb;
	uint16 compressed_len = MSG_ReadShort (msg);
	uint16 uncompressed_len = MSG_ReadShort (msg);
	
	if (uncompressed_len <= 0)
		Com_Error (ERR_DROP, "CL_ParseZPacket: uncompressed_len <= 0");

	if (compressed_len <= 0)
		Com_Error (ERR_DROP, "CL_ParseZPacket: compressed_len <= 0");

	MSG_ReadData (msg, buff_in, compressed_len);

	SZ_Init (&sb, buff_out, uncompressed_len);
	sb.cursize = ZLibDecompress (buff_in, compressed_len, buff_out, uncompressed_len, -15);

	CL_ParseServerMessage(&sb);

	Com_DPrintf ("Got a ZPacket, %d->%d\n", uncompressed_len + 4, compressed_len);
}
示例#5
0
/*
================
CL_ParseSnapshot

If the snapshot is parsed properly, it will be copied to
cl.frame and saved in cl.frames[].  If the snapshot is invalid
for any reason, no changes to the state will be made at all.
================
*/
void CL_ParseSnapshot( msg_t *msg ) {
	int			len;
	clSnapshot_t	*old;
	clSnapshot_t	newSnap;
	int			deltaNum;
	int			oldMessageNum;
	int			i, packetNum;

	// get the reliable sequence acknowledge number
	clc.reliableAcknowledge = MSG_ReadLong( msg );

	// read in the new snapshot to a temporary buffer
	// we will only copy to cl.frame if it is valid
	memset (&newSnap, 0, sizeof(newSnap));

	newSnap.serverCommandNum = clc.serverCommandSequence;
	newSnap.serverTime = MSG_ReadLong( msg );
	newSnap.messageNum = MSG_ReadLong( msg );
	deltaNum = MSG_ReadByte( msg );
	if ( !deltaNum ) {
		newSnap.deltaNum = -1;
	} else {
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
	}
	newSnap.cmdNum = MSG_ReadLong( msg );
	newSnap.snapFlags = MSG_ReadByte( msg );

	// If the frame is delta compressed from data that we
	// no longer have available, we must suck up the rest of
	// the frame, but not use it, then ask for a non-compressed
	// message 
	if ( newSnap.deltaNum <= 0 ) {
		newSnap.valid = qtrue;		// uncompressed frame
		old = NULL;
	} else {
		old = &cl.frames[newSnap.deltaNum & PACKET_MASK];
		if ( !old->valid ) {
			// should never happen
			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
		} else if ( old->messageNum != newSnap.deltaNum ) {
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_Printf ("Delta frame too old.\n");
		} else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES ) {
			Com_Printf ("Delta parseEntitiesNum too old.\n");
		} else {
			newSnap.valid = qtrue;	// valid delta parse
		}
	}

	// read areamask
	len = MSG_ReadByte( msg );
	MSG_ReadData( msg, &newSnap.areamask, len);

	// read playerinfo
	SHOWNET( msg, "playerstate" );
	if ( old ) {
		MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
	} else {
		MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
	}

	// read packet entities
	SHOWNET( msg, "packet entities" );
	CL_ParsePacketEntities( msg, old, &newSnap );

	// if not valid, dump the entire thing now that it has
	// been properly read
	if ( !newSnap.valid ) {
		return;
	}

	// clear the valid flags of any snapshots between the last
	// received and this one
	oldMessageNum = cl.frame.messageNum + 1;

	if ( cl.frame.messageNum - oldMessageNum >= PACKET_BACKUP ) {
		oldMessageNum = cl.frame.messageNum - ( PACKET_BACKUP - 1 );
	}
	for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
		cl.frames[oldMessageNum & PACKET_MASK].valid = qfalse;
	}

	// copy to the current good spot
	cl.frame = newSnap;

	// calculate ping time
	for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
		packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
		if ( cl.frame.cmdNum == cl.packetCmdNumber[ packetNum ] ) {
			cl.frame.ping = cls.realtime - cl.packetTime[ packetNum ];
			break;
		}
	}
	// save the frame off in the backup array for later delta comparisons
	cl.frames[cl.frame.messageNum & PACKET_MASK] = cl.frame;

	if (cl_shownet->integer == 3) {
		Com_Printf ("   frame:%i  delta:%i\n", cl.frame.messageNum,
		cl.frame.deltaNum);
	}

	// actions for valid frames
	cl.newSnapshots = qtrue;
}
示例#6
0
static
void SV_UserVoip( client_t *cl, msg_t *msg ) {
	const int sender = (int) (cl - svs.clients);
	const int generation = MSG_ReadByte(msg);
	const int sequence = MSG_ReadLong(msg);
	const int frames = MSG_ReadByte(msg);
	const int recip1 = MSG_ReadLong(msg);
	const int recip2 = MSG_ReadLong(msg);
	const int recip3 = MSG_ReadLong(msg);
	const int packetsize = MSG_ReadShort(msg);
	byte encoded[sizeof (cl->voipPacket[0].data)];
	client_t *client = NULL;
	voipServerPacket_t *packet = NULL;
	int i;

	if (generation < 0)
		return;   // short/invalid packet, bail.
	else if (sequence < 0)
		return;   // short/invalid packet, bail.
	else if (frames < 0)
		return;   // short/invalid packet, bail.
	else if (recip1 < 0)
		return;   // short/invalid packet, bail.
	else if (recip2 < 0)
		return;   // short/invalid packet, bail.
	else if (recip3 < 0)
		return;   // short/invalid packet, bail.
	else if (packetsize < 0)
		return;   // short/invalid packet, bail.

	if (packetsize > sizeof (encoded)) {  // overlarge packet?
		int bytesleft = packetsize;
		while (bytesleft) {
			int br = bytesleft;
			if (br > sizeof (encoded))
				br = sizeof (encoded);
			MSG_ReadData(msg, encoded, br);
			bytesleft -= br;
		}
		return;   // overlarge packet, bail.
	}

	MSG_ReadData(msg, encoded, packetsize);

	if (SV_ShouldIgnoreVoipSender(cl))
		return;   // Blacklisted, disabled, etc.

	// !!! FIXME: see if we read past end of msg...

	// !!! FIXME: reject if not speex narrowband codec.
	// !!! FIXME: decide if this is bogus data?

	// (the three recip* values are 31 bits each (ignores sign bit so we can
	//  get a -1 error from MSG_ReadLong() ... ), allowing for 93 clients.)
	assert( sv_maxclients->integer < 93 );

	// decide who needs this VoIP packet sent to them...
	for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
		if (client->state != CS_ACTIVE)
			continue;  // not in the game yet, don't send to this guy.
		else if (i == sender)
			continue;  // don't send voice packet back to original author.
		else if (!client->hasVoip)
			continue;  // no VoIP support, or support disabled.
		else if (client->muteAllVoip)
			continue;  // client is ignoring everyone.
		else if (client->ignoreVoipFromClient[sender])
			continue;  // client is ignoring this talker.
		else if (*cl->downloadName)   // !!! FIXME: possible to DoS?
			continue;  // no VoIP allowed if downloading, to save bandwidth.
		else if ( ((i >= 0) && (i < 31)) && ((recip1 & (1 << (i-0))) == 0) )
			continue;  // not addressed to this player.
		else if ( ((i >= 31) && (i < 62)) && ((recip2 & (1 << (i-31))) == 0) )
			continue;  // not addressed to this player.
		else if ( ((i >= 62) && (i < 93)) && ((recip3 & (1 << (i-62))) == 0) )
			continue;  // not addressed to this player.

		// Transmit this packet to the client.
		// !!! FIXME: I don't like this queueing system.
		if (client->queuedVoipPackets >= (sizeof (client->voipPacket) / sizeof (client->voipPacket[0]))) {
			Com_Printf("Too many VoIP packets queued for client #%d\n", i);
			continue;  // no room for another packet right now.
		}

		packet = &client->voipPacket[client->queuedVoipPackets];
		packet->sender = sender;
		packet->frames = frames;
		packet->len = packetsize;
		packet->generation = generation;
		packet->sequence = sequence;
		memcpy(packet->data, encoded, packetsize);
		client->queuedVoipPackets++;
	}
}
示例#7
0
/*
* CL_ParseGetServersResponseMessage
* Handle a reply from getservers message to master server
*/
static void CL_ParseGetServersResponseMessage( msg_t *msg, qboolean extended )
{
	const char *header;
	char adrString[64];
	qbyte addr[16];
	unsigned short port;
	netadr_t adr;

	MSG_BeginReading( msg );
	MSG_ReadLong( msg ); // skip the -1

	//jump over the command name
	header = ( extended ? "getserversExtResponse" : "getserversResponse" );
	if( !MSG_SkipData( msg, strlen( header ) ) )
	{
		Com_Printf( "Invalid master packet ( missing %s )\n", header );
		return;
	}

	while( msg->readcount + 7 <= msg->cursize )
	{
		char prefix = MSG_ReadChar( msg );

		switch( prefix )
		{
		case '\\':
			MSG_ReadData( msg, addr, 4 );
			port = ShortSwap( MSG_ReadShort( msg ) ); // both endians need this swapped.
			Q_snprintfz( adrString, sizeof( adrString ), "%u.%u.%u.%u:%u", addr[0], addr[1], addr[2], addr[3], port );
			break;

		case '/':
			if( extended )
			{
				MSG_ReadData( msg, addr, 16 );
				port = ShortSwap( MSG_ReadShort( msg ) ); // both endians need this swapped.
				Q_snprintfz( adrString, sizeof( adrString ), "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%hu",
								addr[ 0], addr[ 1], addr[ 2], addr[ 3], addr[ 4], addr[ 5], addr[ 6], addr[ 7],
								addr[ 8], addr[ 9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15],
								port );
			}
			else
			{
				Com_Printf( "Invalid master packet ( IPv6 prefix in a non-extended response )\n" );
				return;
			}

			break;

		default:
			Com_Printf( "Invalid master packet ( missing separator )\n" );
			return;
		}

		if( port == 0 )  // last server seen
			return;

		Com_DPrintf( "%s\n", adrString );
		if( !NET_StringToAddress( adrString, &adr ) )
		{
			Com_Printf( "Bad address: %s\n", adrString );
			continue;
		}

		CL_AddServerToList( &masterList, adrString, 0 );
	}
}
示例#8
0
/*
=====================
CL_ParseDownload

A download message has been received from the server
=====================
*/
void CL_ParseDownload( msg_t *msg )
{
	int           size;
	unsigned char data[ MAX_MSGLEN ];
	int           block;

	if ( !*cls.downloadTempName )
	{
		Com_Printf("%s", _( "Server sending download, but no download was requested\n" ));
		CL_AddReliableCommand( "stopdl" );
		return;
	}

	// read the data
	block = MSG_ReadShort( msg );

	// TTimo - www dl
	// if we haven't acked the download redirect yet
	if ( block == -1 )
	{
		if ( !clc.bWWWDl )
		{
			// server is sending us a www download
			Q_strncpyz( cls.originalDownloadName, cls.downloadName, sizeof( cls.originalDownloadName ) );
			Q_strncpyz( cls.downloadName, MSG_ReadString( msg ), sizeof( cls.downloadName ) );
			clc.downloadSize = MSG_ReadLong( msg );
			clc.downloadFlags = MSG_ReadLong( msg );

			Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
			Com_DPrintf( "Server redirected download: %s\n", cls.downloadName );
			clc.bWWWDl = qtrue; // activate wwwdl client loop
			CL_AddReliableCommand( "wwwdl ack" );

			// make sure the server is not trying to redirect us again on a bad checksum
			if ( strstr( clc.badChecksumList, va( "@%s", cls.originalDownloadName ) ) )
			{
				Com_Printf(_( "refusing redirect to %s by server (bad checksum)\n"), cls.downloadName );
				CL_AddReliableCommand( "wwwdl fail" );
				clc.bWWWDlAborting = qtrue;
				return;
			}

			// make downloadTempName an OS path
			Q_strncpyz( cls.downloadTempName, FS_BuildOSPath( Cvar_VariableString( "fs_homepath" ), cls.downloadTempName, "" ),
			            sizeof( cls.downloadTempName ) );
			cls.downloadTempName[ strlen( cls.downloadTempName ) - 1 ] = '\0';

			if ( !DL_BeginDownload( cls.downloadTempName, cls.downloadName, com_developer->integer ) )
			{
				// setting bWWWDl to false after sending the wwwdl fail doesn't work
				// not sure why, but I suspect we have to eat all remaining block -1 that the server has sent us
				// still leave a flag so that CL_WWWDownload is inactive
				// we count on server sending us a gamestate to start up clean again
				CL_AddReliableCommand( "wwwdl fail" );
				clc.bWWWDlAborting = qtrue;
				Com_Printf(_( "Failed to initialize download for '%s'\n"), cls.downloadName );
			}

			// Check for a disconnected download
			// we'll let the server disconnect us when it gets the bbl8r message
			if ( clc.downloadFlags & ( 1 << DL_FLAG_DISCON ) )
			{
				CL_AddReliableCommand( "wwwdl bbl8r" );
				cls.bWWWDlDisconnected = qtrue;
			}

			return;
		}
		else
		{
			// server keeps sending that message till we ack it, eat and ignore
			//MSG_ReadLong( msg );
			MSG_ReadString( msg );
			MSG_ReadLong( msg );
			MSG_ReadLong( msg );
			return;
		}
	}

	if ( !block )
	{
		// block zero is special, contains file size
		clc.downloadSize = MSG_ReadLong( msg );

		Cvar_SetValue( "cl_downloadSize", clc.downloadSize );

		if ( clc.downloadSize < 0 )
		{
			Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) );
		}
	}

	size = MSG_ReadShort( msg );

	if ( size < 0 || size > sizeof( data ) )
	{
		Com_Error( ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size );
	}

	MSG_ReadData( msg, data, size );

	if ( clc.downloadBlock != block )
	{
		Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block );
		return;
	}

	// open the file if not opened yet
	if ( !clc.download )
	{
		clc.download = FS_SV_FOpenFileWrite( cls.downloadTempName );

		if ( !clc.download )
		{
			Com_Printf(_( "Could not create %s\n"), cls.downloadTempName );
			CL_AddReliableCommand( "stopdl" );
			CL_NextDownload();
			return;
		}
	}

	if ( size )
	{
		FS_Write( data, size, clc.download );
	}

	CL_AddReliableCommand( va( "nextdl %d", clc.downloadBlock ) );
	clc.downloadBlock++;

	clc.downloadCount += size;

	// So UI gets access to it
	Cvar_SetValue( "cl_downloadCount", clc.downloadCount );

	if ( !size )
	{
		// A zero length block means EOF
		if ( clc.download )
		{
			FS_FCloseFile( clc.download );
			clc.download = 0;

			// rename the file
			FS_SV_Rename( cls.downloadTempName, cls.downloadName );
		}

		*cls.downloadTempName = *cls.downloadName = 0;
		Cvar_Set( "cl_downloadName", "" );

		// send intentions now
		// We need this because without it, we would hold the last nextdl and then start
		// loading right away.  If we take a while to load, the server is happily trying
		// to send us that last block over and over.
		// Write it twice to help make sure we acknowledge the download
		CL_WritePacket();
		CL_WritePacket();

		// get another file if needed
		CL_NextDownload();
	}
}
示例#9
0
/*
=====================
CL_ParseVoip

A VoIP message has been received from the server
=====================
*/
static
void CL_ParseVoip ( msg_t *msg, qboolean ignoreData ) {
	static short decoded[VOIP_MAX_PACKET_SAMPLES*4]; // !!! FIXME: don't hard code

	const int sender = MSG_ReadShort(msg);
	const int generation = MSG_ReadByte(msg);
	const int sequence = MSG_ReadLong(msg);
	const int frames = MSG_ReadByte(msg);
	const int packetsize = MSG_ReadShort(msg);
	const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT);
	unsigned char encoded[4000];
	int	numSamples;
	int seqdiff;
	int written = 0;
	int i;

	Com_DPrintf("VoIP: %d-byte packet from client %d\n", packetsize, sender);

	if (sender < 0)
		return;   // short/invalid packet, bail.
	else if (generation < 0)
		return;   // short/invalid packet, bail.
	else if (sequence < 0)
		return;   // short/invalid packet, bail.
	else if (frames < 0)
		return;   // short/invalid packet, bail.
	else if (packetsize < 0)
		return;   // short/invalid packet, bail.

	if (packetsize > sizeof (encoded)) {  // overlarge packet?
		int bytesleft = packetsize;
		while (bytesleft) {
			int br = bytesleft;
			if (br > sizeof (encoded))
				br = sizeof (encoded);
			MSG_ReadData(msg, encoded, br);
			bytesleft -= br;
		}
		return;   // overlarge packet, bail.
	}

	MSG_ReadData(msg, encoded, packetsize);

	if (ignoreData) {
		return; // just ignore legacy speex voip data
	} else if (!clc.voipCodecInitialized) {
		return;   // can't handle VoIP without libopus!
	} else if (sender >= MAX_CLIENTS) {
		return;   // bogus sender.
	} else if (CL_ShouldIgnoreVoipSender(sender)) {
		return;   // Channel is muted, bail.
	}

	// !!! FIXME: make sure data is narrowband? Does decoder handle this?

	Com_DPrintf("VoIP: packet accepted!\n");

	seqdiff = sequence - clc.voipIncomingSequence[sender];

	// This is a new "generation" ... a new recording started, reset the bits.
	if (generation != clc.voipIncomingGeneration[sender]) {
		Com_DPrintf("VoIP: new generation %d!\n", generation);
		opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
		clc.voipIncomingGeneration[sender] = generation;
		seqdiff = 0;
	} else if (seqdiff < 0) {   // we're ahead of the sequence?!
		// This shouldn't happen unless the packet is corrupted or something.
		Com_DPrintf("VoIP: misordered sequence! %d < %d!\n",
		            sequence, clc.voipIncomingSequence[sender]);
		// reset the decoder just in case.
		opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
		seqdiff = 0;
	} else if (seqdiff * VOIP_MAX_PACKET_SAMPLES*2 >= sizeof (decoded)) { // dropped more than we can handle?
		// just start over.
		Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n",
		            seqdiff, sender);
		opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
		seqdiff = 0;
	}

	if (seqdiff != 0) {
		Com_DPrintf("VoIP: Dropped %d frames from client #%d\n",
		            seqdiff, sender);
		// tell opus that we're missing frames...
		for (i = 0; i < seqdiff; i++) {
			assert((written + VOIP_MAX_PACKET_SAMPLES) * 2 < sizeof (decoded));
			numSamples = opus_decode(clc.opusDecoder[sender], NULL, 0, decoded + written, VOIP_MAX_PACKET_SAMPLES, 0);
			if ( numSamples <= 0 ) {
				Com_DPrintf("VoIP: Error decoding frame %d from client #%d\n", i, sender);
				continue;
			}
			written += numSamples;
		}
	}

	numSamples = opus_decode(clc.opusDecoder[sender], encoded, packetsize, decoded + written, ARRAY_LEN(decoded) - written, 0);

	if ( numSamples <= 0 ) {
		Com_DPrintf("VoIP: Error decoding voip data from client #%d\n", sender);
		numSamples = 0;
	}

	#if 0
	static FILE *encio = NULL;
	if (encio == NULL) encio = fopen("voip-incoming-encoded.bin", "wb");
	if (encio != NULL) { fwrite(encoded, len, 1, encio); fflush(encio); }
	static FILE *decio = NULL;
	if (decio == NULL) decio = fopen("voip-incoming-decoded.bin", "wb");
	if (decio != NULL) { fwrite(decoded+written, clc.speexFrameSize*2, 1, decio); fflush(decio); }
	#endif

	written += numSamples;

	Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
	            written * 2, written, frames);

	if(written > 0)
		CL_PlayVoip(sender, written, (const byte *) decoded, flags);

	clc.voipIncomingSequence[sender] = sequence + frames;
}
示例#10
0
void
CL_ParseFrame(void)
{
    int cmd;
    int len;
    frame_t *old;

    memset(&cl.frame, 0, sizeof(cl.frame));

    cl.frame.serverframe = MSG_ReadLong(&net_message);
    cl.frame.deltaframe = MSG_ReadLong(&net_message);
    cl.frame.servertime = cl.frame.serverframe * 100;

    /* BIG HACK to let old demos continue to work */
    if (cls.serverProtocol != 26)
    {
        cl.surpressCount = MSG_ReadByte(&net_message);
    }

    if (cl_shownet->value == 3)
    {
        Com_Printf("   frame:%i  delta:%i\n", cl.frame.serverframe,
                   cl.frame.deltaframe);
    }

    /* If the frame is delta compressed from data that we
       no longer have available, we must suck up the rest of
       the frame, but not use it, then ask for a non-compressed
       message */
    if (cl.frame.deltaframe <= 0)
    {
        cl.frame.valid = true; /* uncompressed frame */
        old = NULL;
        cls.demowaiting = false; /* we can start recording now */
    }
    else
    {
        old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];

        if (!old->valid)
        {
            /* should never happen */
            Com_Printf("Delta from invalid frame (not supposed to happen!).\n");
        }

        if (old->serverframe != cl.frame.deltaframe)
        {
            /* The frame that the server did the delta from
               is too old, so we can't reconstruct it properly. */
            Com_Printf("Delta frame too old.\n");
        }
        else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES -
                 128)
        {
            Com_Printf("Delta parse_entities too old.\n");
        }
        else
        {
            cl.frame.valid = true; /* valid delta parse */
        }
    }

    /* clamp time */
    if (cl.time > cl.frame.servertime)
    {
        cl.time = cl.frame.servertime;
    }

    else if (cl.time < cl.frame.servertime - 100)
    {
        cl.time = cl.frame.servertime - 100;
    }

    /* read areabits */
    len = MSG_ReadByte(&net_message);
    MSG_ReadData(&net_message, &cl.frame.areabits, len);

    /* read playerinfo */
    cmd = MSG_ReadByte(&net_message);
    SHOWNET(svc_strings[cmd]);

    if (cmd != svc_playerinfo)
    {
        Com_Error(ERR_DROP, "CL_ParseFrame: 0x%X not playerinfo", cmd);
    }

    CL_ParsePlayerstate(old, &cl.frame);

    /* read packet entities */
    cmd = MSG_ReadByte(&net_message);
    SHOWNET(svc_strings[cmd]);

    if (cmd != svc_packetentities)
    {
        Com_Error(ERR_DROP, "CL_ParseFrame: 0x%X not packetentities", cmd);
    }

    CL_ParsePacketEntities(old, &cl.frame);

    /* save the frame off in the backup array for later delta comparisons */
    cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;

    if (cl.frame.valid)
    {
        /* getting a valid frame message ends the connection process */
        if (cls.state != ca_active)
        {
            cls.state = ca_active;
            cl.force_refdef = true;
            cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0] * 0.125f;
            cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1] * 0.125f;
            cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2] * 0.125f;
            VectorCopy(cl.frame.playerstate.viewangles, cl.predicted_angles);

            if ((cls.disable_servercount != cl.servercount) && cl.refresh_prepped)
            {
                SCR_EndLoadingPlaque();  /* get rid of loading plaque */
            }

            cl.sound_prepped = true;
        }

        /* fire entity events */
        CL_FireEntityEvents(&cl.frame);

        if (!(!cl_predict->value ||
                (cl.frame.playerstate.pmove.pm_flags &
                 PMF_NO_PREDICTION)))
        {
            CL_CheckPredictionError();
        }
    }
}
示例#11
0
static
void SV_UserVoip(client_t *cl, msg_t *msg)
{
	int sender, generation, sequence, frames, packetsize;
	uint8_t recips[(MAX_CLIENTS + 7) / 8];
	int flags;
	byte encoded[sizeof(cl->voipPacket[0]->data)];
	client_t *client = NULL;
	voipServerPacket_t *packet = NULL;
	int i;

	sender = cl - svs.clients;
	generation = MSG_ReadByte(msg);
	sequence = MSG_ReadLong(msg);
	frames = MSG_ReadByte(msg);
	MSG_ReadData(msg, recips, sizeof(recips));
	flags = MSG_ReadByte(msg);
	packetsize = MSG_ReadShort(msg);

	if (msg->readcount > msg->cursize)
		return;   // short/invalid packet, bail.

	if (packetsize > sizeof (encoded)) {  // overlarge packet?
		int bytesleft = packetsize;
		while (bytesleft) {
			int br = bytesleft;
			if (br > sizeof (encoded))
				br = sizeof (encoded);
			MSG_ReadData(msg, encoded, br);
			bytesleft -= br;
		}
		return;   // overlarge packet, bail.
	}

	MSG_ReadData(msg, encoded, packetsize);

	if (SV_ShouldIgnoreVoipSender(cl))
		return;   // Blacklisted, disabled, etc.

	// !!! FIXME: see if we read past end of msg...

	// !!! FIXME: reject if not speex narrowband codec.
	// !!! FIXME: decide if this is bogus data?

	// decide who needs this VoIP packet sent to them...
	for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
		if (client->state != CS_ACTIVE)
			continue;  // not in the game yet, don't send to this guy.
		else if (i == sender)
			continue;  // don't send voice packet back to original author.
		else if (!client->hasVoip)
			continue;  // no VoIP support, or unsupported protocol
		else if (client->muteAllVoip)
			continue;  // client is ignoring everyone.
		else if (client->ignoreVoipFromClient[sender])
			continue;  // client is ignoring this talker.
		else if (*cl->downloadName)   // !!! FIXME: possible to DoS?
			continue;  // no VoIP allowed if downloading, to save bandwidth.

		if(Com_IsVoipTarget(recips, sizeof(recips), i))
			flags |= VOIP_DIRECT;
		else
			flags &= ~VOIP_DIRECT;

		if (!(flags & (VOIP_SPATIAL | VOIP_DIRECT)))
			continue;  // not addressed to this player.

		// Transmit this packet to the client.
		if (client->queuedVoipPackets >= ARRAY_LEN(client->voipPacket)) {
			Com_Printf("Too many VoIP packets queued for client #%d\n", i);
			continue;  // no room for another packet right now.
		}

		packet = Z_Malloc(sizeof(*packet));
		packet->sender = sender;
		packet->frames = frames;
		packet->len = packetsize;
		packet->generation = generation;
		packet->sequence = sequence;
		packet->flags = flags;
		memcpy(packet->data, encoded, packetsize);

		client->voipPacket[(client->queuedVoipIndex + client->queuedVoipPackets) % ARRAY_LEN(client->voipPacket)] = packet;
		client->queuedVoipPackets++;
	}
}
示例#12
0
static void demoFrameUnpack( msg_t *msg, demoFrame_t *oldFrame, demoFrame_t *newFrame ) {
	int last;
	qboolean isDelta = MSG_ReadBits( msg, 1 ) ? qfalse : qtrue;
	if (!isDelta)
		oldFrame = 0;

	newFrame->serverTime = MSG_ReadLong( msg );
	/* Read config strings */
	newFrame->string.data[0] = 0;
	newFrame->string.used = 1;
	last = 0;
	/* Extract config strings */
	while ( 1 ) {
		int i, num = MSG_ReadShort( msg );
		if (!isDelta ) {
			for (i = last;i<num;i++)
				newFrame->string.offsets[i] = 0;
		} else {
			for (i = last;i<num;i++)
				demoFrameAddString( &newFrame->string, i, oldFrame->string.data + oldFrame->string.offsets[i] );
		}
		if (num < MAX_CONFIGSTRINGS) {
			demoFrameAddString( &newFrame->string, num, MSG_ReadBigString( msg ) );
		} else {
			break;
		}
		last = num + 1;
	}
    /* Extract player states */
	Com_Memset( newFrame->clientData, 0, sizeof( newFrame->clientData ));
	last = MSG_ReadByte( msg );
	while (last < MAX_CLIENTS) {
		playerState_t *oldPlayer, *newPlayer;
		newFrame->clientData[last] = 1;
		oldPlayer = isDelta && oldFrame->clientData[last] ? &oldFrame->clients[last] : &demoNullPlayerState;
		newPlayer = &newFrame->clients[last];
		MSG_ReadDeltaPlayerstate( msg, oldPlayer, newPlayer );
		last = MSG_ReadByte( msg );
	}
	/* Extract entity states */
	last = 0;
	while ( 1 ) {
		int i, num = MSG_ReadBits( msg, GENTITYNUM_BITS );
		entityState_t *oldEntity, *newEntity;	
		if ( isDelta ) {
			for (i = last;i<num;i++)
				if (oldFrame->entities[i].number == i)
					newFrame->entities[i] = oldFrame->entities[i];
				else
					newFrame->entities[i].number = MAX_GENTITIES - 1;
		} else {
			for (i = last;i<num;i++)
				newFrame->entities[i].number = MAX_GENTITIES - 1;
		}
		if (num < MAX_GENTITIES - 1) {
			if (isDelta) {
				oldEntity = &oldFrame->entities[num];
				if (oldEntity->number != num)
					oldEntity = &demoNullEntityState;
			} else {
				oldEntity = &demoNullEntityState;
			}
			newEntity = &newFrame->entities[i];
			MSG_ReadDeltaEntity( msg, oldEntity, newEntity, num );
		} else
			break;
		last = num + 1;
	}
	/* Read the area mask */
	newFrame->areaUsed = MSG_ReadByte( msg );
	MSG_ReadData( msg, newFrame->areamask, newFrame->areaUsed );
	/* Read the command string data */
	newFrame->commandUsed = MSG_ReadLong( msg );
	MSG_ReadData( msg, newFrame->commandData, newFrame->commandUsed );
}
示例#13
0
void demoConvert( const char *oldName, const char *newBaseName, qboolean smoothen ) {
	fileHandle_t	oldHandle = 0;
	fileHandle_t	newHandle = 0;
	int				temp;
	int				oldSize;
	int				msgSequence;
	msg_t			oldMsg;
	byte			oldData[ MAX_MSGLEN ];
	int				oldTime, nextTime, fullTime;
	int				clientNum;
	demoFrame_t		*workFrame;
	int				parseEntitiesNum = 0;
	demoConvert_t	*convert;
	char			bigConfigString[BIG_INFO_STRING];
	int				bigConfigNumber;
	const char		*s;
	clSnapshot_t	*oldSnap = 0;
	clSnapshot_t	*newSnap;
	int				levelCount = 0;
	char			newName[MAX_OSPATH];

	oldSize = FS_FOpenFileRead( oldName, &oldHandle, qtrue );
	if (!oldHandle) {
		Com_Printf("Failed to open %s for conversion.", oldName);
		return;
	}
	/* Alloc some memory */
	convert = Z_Malloc( sizeof( demoConvert_t) );
	/* Initialize the first workframe's strings */
	while (oldSize > 0) {
		MSG_Init( &oldMsg, oldData, sizeof( oldData ) );
		/* Read the sequence number */
		if (FS_Read( &convert->messageNum, 4, oldHandle) != 4)
			goto conversionerror;
		convert->messageNum = LittleLong( convert->messageNum );
		oldSize -= 4;
		/* Read the message size */
		if (FS_Read( &oldMsg.cursize,4, oldHandle) != 4)
			goto conversionerror;
		oldSize -= 4;
		oldMsg.cursize = LittleLong( oldMsg.cursize );
		/* Negative size signals end of demo */
		if (oldMsg.cursize < 0)
			break;
		if ( oldMsg.cursize > oldMsg.maxsize ) 
			goto conversionerror;
		/* Read the actual message */
		if (FS_Read( oldMsg.data, oldMsg.cursize, oldHandle ) != oldMsg.cursize)
			goto conversionerror;
		oldSize -= oldMsg.cursize;
		// init the bitstream
		MSG_BeginReading( &oldMsg );
		// Skip the reliable sequence acknowledge number
		MSG_ReadLong( &oldMsg );
		//
		// parse the message
		//
		while ( 1 ) {
			byte cmd;
			if ( oldMsg.readcount > oldMsg.cursize ) {
				Com_Printf ("Demo conversion, read past end of server message.\n");
				goto conversionerror;
			}
            cmd = MSG_ReadByte( &oldMsg );
			if ( cmd == svc_EOF) {
                break;
			}
			workFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES ];
			// other commands
			switch ( cmd ) {
			default:
				Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
				break;			
			case svc_nop:
				break;
			case svc_serverCommand:
				temp = MSG_ReadLong( &oldMsg );
				s = MSG_ReadString( &oldMsg );
				if (temp<=msgSequence)
					break;
//				Com_Printf( " server command %s\n", s );
				msgSequence = temp;
				Cmd_TokenizeString( s );
	
				if ( !Q_stricmp( Cmd_Argv(0), "bcs0" ) ) {
					bigConfigNumber = atoi( Cmd_Argv(1) );
					Q_strncpyz( bigConfigString, Cmd_Argv(2), sizeof( bigConfigString ));
					break;
				}
				if ( !Q_stricmp( Cmd_Argv(0), "bcs1" ) ) {
					Q_strcat( bigConfigString, sizeof( bigConfigString ), Cmd_Argv(2));
					break;
				}
				if ( !Q_stricmp( Cmd_Argv(0), "bcs2" ) ) {
					Q_strcat( bigConfigString, sizeof( bigConfigString ), Cmd_Argv(2));
					demoFrameAddString( &workFrame->string, bigConfigNumber, bigConfigString );
					break;
				}
				if ( !Q_stricmp( Cmd_Argv(0), "cs" ) ) {
					int num = atoi( Cmd_Argv(1) );
					s = Cmd_ArgsFrom( 2 );
					demoFrameAddString( &workFrame->string, num, Cmd_ArgsFrom( 2 ) );
					break;
				}
				if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
					int len = strlen( s ) + 1;
					char *dst;
					if (workFrame->commandUsed + len + 1 > sizeof( workFrame->commandData)) {
						Com_Printf("Overflowed state command data.\n");
						goto conversionerror;
					}
					dst = workFrame->commandData + workFrame->commandUsed;
					*dst = clientNum;
					Com_Memcpy( dst+1, s, len );
					workFrame->commandUsed += len + 1;
				}
				break;
			case svc_gamestate:
				if (newHandle) {
					FS_FCloseFile( newHandle );
					newHandle = 0;
				}
				if (levelCount) {
					Com_sprintf( newName, sizeof( newName ), "%s.%d.mme", newBaseName, levelCount );
				} else {
					Com_sprintf( newName, sizeof( newName ), "%s.mme", newBaseName );
				}
				fullTime = -1;
				clientNum = -1;
				oldTime = -1;
				Com_Memset( convert, 0, sizeof( *convert ));
				convert->frames[0].string.used = 1;
				levelCount++;
				newHandle = FS_FOpenFileWrite( newName );
				if (!newHandle) {
					Com_Printf("Failed to open %s for target conversion target.\n", newName);
					goto conversionerror;
					return;
				} else {
					FS_Write ( demoHeader, strlen( demoHeader ), newHandle );
				}
				Com_sprintf( newName, sizeof( newName ), "%s.txt", newBaseName );
				workFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES ];
				msgSequence = MSG_ReadLong( &oldMsg );
				while( 1 ) {
					cmd = MSG_ReadByte( &oldMsg );
					if (cmd == svc_EOF)
						break;
					if ( cmd == svc_configstring) {
						int		num;
						const char *s;
						num = MSG_ReadShort( &oldMsg );
						s = MSG_ReadBigString( &oldMsg );
						demoFrameAddString( &workFrame->string, num, s );
					} else if ( cmd == svc_baseline ) {
						int num = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS );
						if ( num < 0 || num >= MAX_GENTITIES ) {
							Com_Printf( "Baseline number out of range: %i.\n", num );
							goto conversionerror;
						}
						MSG_ReadDeltaEntity( &oldMsg, &demoNullEntityState, &convert->entityBaselines[num], num );
					} else {
						Com_Printf( "Unknown block while converting demo gamestate.\n" );
						goto conversionerror;
					}
				}
				clientNum = MSG_ReadLong( &oldMsg );
				/* Skip the checksum feed */
				MSG_ReadLong( &oldMsg );
				break;
			case svc_snapshot:
				nextTime = MSG_ReadLong( &oldMsg );
				/* Delta number, not needed */
				newSnap = &convert->snapshots[convert->messageNum & PACKET_MASK];
				Com_Memset (newSnap, 0, sizeof(*newSnap));
				newSnap->deltaNum = MSG_ReadByte( &oldMsg );
				newSnap->messageNum = convert->messageNum;
				if (!newSnap->deltaNum) {
					newSnap->deltaNum = -1;
					newSnap->valid = qtrue;		// uncompressed frame
					oldSnap  = NULL;
				} else {
					newSnap->deltaNum = newSnap->messageNum - newSnap->deltaNum;
					oldSnap = &convert->snapshots[newSnap->deltaNum & PACKET_MASK];
					if (!oldSnap->valid) {
						Com_Printf( "Delta snapshot without base.\n" );
						goto conversionerror;
					} else if (oldSnap->messageNum != newSnap->deltaNum) {
						// The frame that the server did the delta from
						// is too old, so we can't reconstruct it properly.
						Com_Printf ("Delta frame too old.\n");
					} else if ( parseEntitiesNum - oldSnap->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
						Com_Printf ("Delta parseEntitiesNum too old.\n");
					} else {
						newSnap->valid = qtrue;	// valid delta parse
					}
				}

				/* Snapflags, not needed */
				newSnap->snapFlags = MSG_ReadByte( &oldMsg );
				// read areamask
				workFrame->areaUsed = MSG_ReadByte( &oldMsg );
				MSG_ReadData( &oldMsg, workFrame->areamask, workFrame->areaUsed );
				if (clientNum <0 || clientNum >= MAX_CLIENTS) {
					Com_Printf("Got snapshot with invalid client.\n");
					goto conversionerror;
				}
				MSG_ReadDeltaPlayerstate( &oldMsg, oldSnap ? &oldSnap->ps : &demoNullPlayerState, &newSnap->ps );
				/* Read the individual entities */
				newSnap->parseEntitiesNum = parseEntitiesNum;
				newSnap->numEntities = 0;
				Com_Memset( workFrame->entityData, 0, sizeof( workFrame->entityData ));

				/* The beast that is entity parsing */
				{
				int			newnum;
				entityState_t	*oldstate, *newstate;
				int			oldindex = 0;
				int			oldnum;
				newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS );
				while ( 1 ) {
					// read the entity index number
					if (oldSnap && oldindex < oldSnap->numEntities) {
						oldstate = &convert->parseEntities[(oldSnap->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
						oldnum = oldstate->number;
					} else {
						oldstate = 0;
						oldnum = 99999;
					}
					newstate = &convert->parseEntities[parseEntitiesNum];
					if ( !oldstate && (newnum == (MAX_GENTITIES-1))) {
						break;
					} else if ( oldnum < newnum ) {
						*newstate = *oldstate;
						oldindex++;
					} else if (oldnum == newnum) {
						oldindex++;
						MSG_ReadDeltaEntity( &oldMsg, oldstate, newstate, newnum );
						if ( newstate->number != MAX_GENTITIES-1)
							workFrame->entityData[ newstate->number ] = 1;
						newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS );
					} else if (oldnum > newnum) {
						MSG_ReadDeltaEntity( &oldMsg, &convert->entityBaselines[newnum], newstate , newnum );
						if ( newstate->number != MAX_GENTITIES-1)
							workFrame->entityData[ newstate->number ] = 1;
						newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS );
					}
					if (newstate->number == MAX_GENTITIES-1)
						continue;
					parseEntitiesNum++;
					parseEntitiesNum &= (MAX_PARSE_ENTITIES-1);
					newSnap->numEntities++;
				}}
				/* Stop processing this further since it's an invalid snap due to lack of delta data */
				if (!newSnap->valid)
					break;

				/* Skipped snapshots will be set invalid in the circular buffer */
				if ( newSnap->messageNum - convert->lastMessageNum >= PACKET_BACKUP ) {
					convert->lastMessageNum = newSnap->messageNum - ( PACKET_BACKUP - 1 );
				}
				for ( ; convert->lastMessageNum < newSnap->messageNum ; convert->lastMessageNum++ ) {
					convert->snapshots[convert->lastMessageNum & PACKET_MASK].valid = qfalse;
				}
				convert->lastMessageNum = newSnap->messageNum + 1;

				/* compress the frame into the new format */
				if (nextTime > oldTime) {
					demoFrame_t *cleanFrame;
					int writeIndex;
					for (temp = 0;temp<newSnap->numEntities;temp++) {
						int p = (newSnap->parseEntitiesNum+temp) & (MAX_PARSE_ENTITIES-1);
						entityState_t *newState = &convert->parseEntities[p];
						workFrame->entities[newState->number] = *newState;
					}
					workFrame->clientData[clientNum] = 1;
					workFrame->clients[clientNum] = newSnap->ps;
					workFrame->serverTime = nextTime;

					/* Which frame from the cache to save */
					writeIndex = convert->frameIndex - (DEMOCONVERTFRAMES/2);
					if (writeIndex >= 0) {
						const demoFrame_t *newFrame;
						msg_t writeMsg;
						// init the message
						MSG_Init( &writeMsg, demoBuffer, sizeof (demoBuffer));
						MSG_Clear( &writeMsg );
						MSG_Bitstream( &writeMsg );
						newFrame = &convert->frames[ writeIndex  % DEMOCONVERTFRAMES];
						if ( smoothen )
							demoFrameInterpolate( convert->frames, DEMOCONVERTFRAMES, writeIndex );
						if ( nextTime > fullTime || writeIndex <= 0 ) {
							/* Plan the next time for a full write */
							fullTime = nextTime + 2000;
							demoFramePack( &writeMsg, newFrame, 0 );
						} else {
							const demoFrame_t *oldFrame = &convert->frames[ ( writeIndex -1 ) % DEMOCONVERTFRAMES];
							demoFramePack( &writeMsg, newFrame, oldFrame );
						}
						/* Write away the new data in the msg queue */
						temp = LittleLong( writeMsg.cursize );
						FS_Write (&temp, 4, newHandle );
						FS_Write ( writeMsg.data , writeMsg.cursize, newHandle );
					}

					/* Clean up the upcoming frame for all new changes */
					convert->frameIndex++;
					cleanFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES];
					cleanFrame->serverTime = 0;
					for (temp = 0;temp<MAX_GENTITIES;temp++)
						cleanFrame->entities[temp].number = MAX_GENTITIES-1;
					Com_Memset( cleanFrame->clientData, 0, sizeof ( cleanFrame->clientData ));
					Com_Memcpy( cleanFrame->string.data, workFrame->string.data, workFrame->string.used );
					Com_Memcpy( cleanFrame->string.offsets, workFrame->string.offsets, sizeof( workFrame->string.offsets ));
					cleanFrame->string.used = workFrame->string.used;
					cleanFrame->commandUsed = 0;
					/* keep track of this last frame's time */
					oldTime = nextTime;
				}
				break;
			case svc_download:
				// read block number
				temp = MSG_ReadShort ( &oldMsg );
				if (!temp)	//0 block, read file size
					MSG_ReadLong( &oldMsg );
				// read block size
				temp = MSG_ReadShort ( &oldMsg );
				// read the data block
				for ( ;temp>0;temp--)
					MSG_ReadByte( &oldMsg );
				break;
			}
		}
	}
conversionerror:
	FS_FCloseFile( oldHandle );
	FS_FCloseFile( newHandle );
	Z_Free( convert );
	return;
}
示例#14
0
// Called when data is received from server
// TODO: store the voip data and then process in the main S_Update() call
void S_Voip_Parse (void)
{
	unsigned int sender;
	int bytes;
	unsigned char data[1024], *start;
	short decodebuf[1024];
	unsigned int decodesamps, len, newseq, drops;
	unsigned char seq, gen;
	float amp = 1;
	unsigned int i;

	sender = MSG_ReadByte ();
	gen = MSG_ReadByte ();
	seq = MSG_ReadByte ();
	bytes = MSG_ReadShort ();

	if (bytes > sizeof (data) || !cl_voip_play.integer || !S_Speex_Init () || (gen & 0xf0)) {
		Com_DPrintf ("skip data: %d\n", bytes);
		MSG_ReadSkip (bytes);
		return;
	}
	MSG_ReadData (data, bytes);

	sender &= MAX_CLIENTS - 1;

	amp = s_speex.decamp[sender];

	decodesamps = 0;
	newseq = 0;
	drops = 0;
	start = data;

	s_speex.lastspoke[sender] = cls.realtime + 0.5;
	if (s_speex.decgen[sender] != gen) {
		speex_bits_reset (&s_speex.decbits[sender]);
		s_speex.decgen[sender] = gen;
		s_speex.decseq[sender] = seq;
	}

	while (bytes > 0) {
		if (decodesamps + s_speex.framesize > sizeof (decodebuf) / sizeof (decodebuf[0])) {
			S_RawAudio (sender, (byte*)decodebuf, s_speex.samplerate, decodesamps, 1, 2);
			decodesamps = 0;
		}

		if (s_speex.decseq[sender] != seq) {
			speex_decode_int (s_speex.decoder[sender], NULL, decodebuf + decodesamps);
			s_speex.decseq[sender]++;
			drops++;
		}
		else {
			bytes--;
			len = *start++;
			speex_bits_read_from (&s_speex.decbits[sender], (char *)start, len);
			bytes -= len;
			start += len;
			speex_decode_int (s_speex.decoder[sender], &s_speex.decbits[sender], decodebuf + decodesamps);
			newseq++;
		}
		if (amp != 1) {
			for (i = decodesamps; i < decodesamps + s_speex.framesize; i++)
				decodebuf[i] *= amp;
		}
		decodesamps += s_speex.framesize;
	}
	s_speex.decseq[sender] += newseq;

	if (drops)
		Con_DPrintf ("%i dropped audio frames\n", drops);

	if (decodesamps > 0) {
		S_RawAudio (sender, (byte*)decodebuf, s_speex.samplerate, decodesamps, 1, 2);
	}
}
示例#15
0
/*
* CL_ParseServerMessage
*/
void CL_ParseServerMessage( msg_t *msg )
{
	int cmd;

	if( cl_shownet->integer == 1 )
	{
		Com_Printf( "%i ", msg->cursize );
	}
	else if( cl_shownet->integer >= 2 )
	{
		Com_Printf( "------------------\n" );
	}

	// parse the message
	while( 1 )
	{
		if( msg->readcount > msg->cursize )
		{
			Com_Error( ERR_DROP, "CL_ParseServerMessage: Bad server message" );
			break;
		}

		cmd = MSG_ReadByte( msg );
		if( cl_debug_serverCmd->integer & 4 )
		{
			if( cmd == -1 )
				Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, "EOF" );
			else
				Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, !svc_strings[cmd] ? "bad" : svc_strings[cmd] );
		}

		if( cmd == -1 )
		{
			SHOWNET( msg, "END OF MESSAGE" );
			break;
		}

		if( cl_shownet->integer >= 2 )
		{
			if( !svc_strings[cmd] )
				Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
			else
				SHOWNET( msg, svc_strings[cmd] );
		}

		// other commands
		switch( cmd )
		{
		default:
			Com_Error( ERR_DROP, "CL_ParseServerMessage: Illegible server message" );
			break;

		case svc_nop:
			// Com_Printf( "svc_nop\n" );
			break;

		case svc_servercmd:
			if( !cls.reliable )
			{
				int cmdNum = MSG_ReadLong( msg );
				if( cmdNum < 0 )
				{
					Com_Error( ERR_DROP, "CL_ParseServerMessage: Invalid cmdNum value received: %i\n",
						cmdNum );
					return;
				}
				if( cmdNum <= cls.lastExecutedServerCommand )
				{
					MSG_ReadString( msg ); // read but ignore
					break;
				}
				cls.lastExecutedServerCommand = cmdNum;
			}
			// fall through
		case svc_servercs: // configstrings from demo files. they don't have acknowledge
			CL_ParseServerCommand( msg );	
			break;

		case svc_serverdata:
			if( cls.state == CA_HANDSHAKE )
			{
				Cbuf_Execute(); // make sure any stuffed commands are done
				CL_ParseServerData( msg );
			}
			else
			{
				return; // ignore rest of the packet (serverdata is always sent alone)
			}
			break;

		case svc_spawnbaseline:
			CL_ParseBaseline( msg );
			break;

		case svc_download:
			CL_ParseDownload( msg );
			break;

		case svc_clcack:
			if( cls.reliable )
			{
				Com_Error( ERR_DROP, "CL_ParseServerMessage: clack message for reliable client\n" );
				return;
			}
			cls.reliableAcknowledge = (unsigned)MSG_ReadLong( msg );
			cls.ucmdAcknowledged = (unsigned)MSG_ReadLong( msg );
			if( cl_debug_serverCmd->integer & 4 )
				Com_Printf( "svc_clcack:reliable cmd ack:%i ucmdack:%i\n", cls.reliableAcknowledge, cls.ucmdAcknowledged );
			break;

		case svc_frame:
			CL_ParseFrame( msg );
			break;

		case svc_demoinfo:
			assert( cls.demo.playing );
			{
				size_t meta_data_maxsize;

				MSG_ReadLong( msg );
				MSG_ReadLong( msg );
				cls.demo.meta_data_realsize = (size_t)MSG_ReadLong( msg );
				meta_data_maxsize = (size_t)MSG_ReadLong( msg );

				// sanity check
				if( cls.demo.meta_data_realsize > meta_data_maxsize ) {
					cls.demo.meta_data_realsize = meta_data_maxsize;
				}
				if( cls.demo.meta_data_realsize > sizeof( cls.demo.meta_data ) ) {
					cls.demo.meta_data_realsize = sizeof( cls.demo.meta_data );
				}

				MSG_ReadData( msg, cls.demo.meta_data, cls.demo.meta_data_realsize );
				MSG_SkipData( msg, meta_data_maxsize - cls.demo.meta_data_realsize );
			}
			break;

		case svc_playerinfo:
		case svc_packetentities:
		case svc_match:
			Com_Error( ERR_DROP, "Out of place frame data" );
			break;

		case svc_extension:
			if( 1 )
			{
				int ext, len;

				ext = MSG_ReadByte( msg );		// extension id
				MSG_ReadByte( msg );			// version number
				len = MSG_ReadShort( msg );		// command length

				switch( ext )
				{
				default:
					// unsupported
					MSG_SkipData( msg, len );
					break;
				}
			}
			break;
		}
	}

	CL_AddNetgraph();

	//
	// if recording demos, copy the message out
	//
	//
	// we don't know if it is ok to save a demo message until
	// after we have parsed the frame
	//
	if( cls.demo.recording && !cls.demo.waiting )
		CL_WriteDemoMessage( msg );
}
示例#16
0
/*
=====================
CL_ParseDownload

A download message has been received from the server
=====================
*/
void CL_ParseDownload ( msg_t *msg ) {
	int		size;
	unsigned char data[MAX_MSGLEN];
	uint16_t block;

	if (!*clc.downloadTempName) {
		Com_Printf("Server sending download, but no download was requested\n");
		CL_AddReliableCommand("stopdl", qfalse);
		return;
	}

	// read the data
	block = MSG_ReadShort ( msg );

	if(!block && !clc.downloadBlock)
	{
		// block zero is special, contains file size
		clc.downloadSize = MSG_ReadLong ( msg );

		Cvar_SetValue( "cl_downloadSize", clc.downloadSize );

		if (clc.downloadSize < 0)
		{
			Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) );
			return;
		}
	}

	size = MSG_ReadShort ( msg );
	if (size < 0 || size > sizeof(data))
	{
		Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk", size);
		return;
	}
	
	MSG_ReadData(msg, data, size);

	if((clc.downloadBlock & 0xFFFF) != block)
	{
		Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", (clc.downloadBlock & 0xFFFF), block);
		return;
	}

	// open the file if not opened yet
	if (!clc.download)
	{
		clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );

		if (!clc.download) {
			Com_Printf( "Could not create %s\n", clc.downloadTempName );
			CL_AddReliableCommand("stopdl", qfalse);
			CL_NextDownload();
			return;
		}
	}

	if (size)
		FS_Write( data, size, clc.download );

	CL_AddReliableCommand(va("nextdl %d", clc.downloadBlock), qfalse);
	clc.downloadBlock++;

	clc.downloadCount += size;

	// So UI gets access to it
	Cvar_SetValue( "cl_downloadCount", clc.downloadCount );

	if (!size) { // A zero length block means EOF
		if (clc.download) {
			FS_FCloseFile( clc.download );
			clc.download = 0;

			// rename the file
			FS_SV_Rename ( clc.downloadTempName, clc.downloadName, qfalse );
		}

		// send intentions now
		// We need this because without it, we would hold the last nextdl and then start
		// loading right away.  If we take a while to load, the server is happily trying
		// to send us that last block over and over.
		// Write it twice to help make sure we acknowledge the download
		CL_WritePacket();
		CL_WritePacket();

		// get another file if needed
		CL_NextDownload ();
	}
}
示例#17
0
/*
================
CL_ParseFrame
================
*/
void CL_ParseFrame (void)
{
	int			cmd;
	int			len;
	frame_t		*old;

	memset (&cl.frame, 0, sizeof(cl.frame));
	cl.frame.serverframe = MSG_ReadLong(&net_message);
	cl.frame.deltaframe = MSG_ReadLong(&net_message);
	cl.frame.servertime = cl.frame.serverframe*100;

	// BIG HACK to let old demos continue to work
	if (cls.serverProtocol != 26)
		cl.surpressCount = MSG_ReadByte(&net_message);

	if (cl_shownet->value == 3)
		Com_Printf ("   frame:%i  delta:%i\n", cl.frame.serverframe, cl.frame.deltaframe);

	// If the frame is delta compressed from data that we
	// no longer have available, we must suck up the rest of
	// the frame, but not use it, then ask for a non-compressed
	// message 
	if (cl.frame.deltaframe <= 0)
	{
		cl.frame.valid = true;		// uncompressed frame
		old = NULL;
		cls.demowaiting = false;	// we can start recording now
	}
	else
	{
		old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];

		if (!old->valid)
		{	// should never happen
			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
		}
		if (old->serverframe != cl.frame.deltaframe)
		{	// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_Printf ("Delta frame too old.\n");
		}
		else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
		{
			Com_Printf ("Delta parse_entities too old.\n");
		}
		else
		{
			cl.frame.valid = true;	// valid delta parse
		}
	}

	// clamp time 
	if (cl.time > cl.frame.servertime)
		cl.time = cl.frame.servertime;
	else if (cl.time < cl.frame.servertime - 100)
		cl.time = cl.frame.servertime - 100;

	// read areabits
	len = MSG_ReadByte(&net_message);
	MSG_ReadData(&net_message, &cl.frame.areabits, len);

	// read playerinfo
	cmd = MSG_ReadByte(&net_message);
	SHOWNET(svc_strings[cmd]);

	if (cmd != svc_playerinfo)
		Com_Error(ERR_DROP, "CL_ParseFrame: not playerinfo");

	CL_ParsePlayerstate(old, &cl.frame);

	// read packet entities
	cmd = MSG_ReadByte(&net_message);
	SHOWNET(svc_strings[cmd]);

	if (cmd != svc_packetentities)
		Com_Error(ERR_DROP, "CL_ParseFrame: not packetentities");

	CL_ParsePacketEntities(old, &cl.frame);


	// save the frame off in the backup array for later delta comparisons
	cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;

	if (cl.frame.valid)
	{
		// getting a valid frame message ends the connection process
		if (cls.state != ca_active)
		{
			cls.state = ca_active;
			//cl_scores_setinuse_all(false); // jitscores - clear scoreboard
			cl.force_refdef = true;
			cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
			cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
			cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
			VectorCopy(cl.frame.playerstate.viewangles, cl.predicted_angles);

			if (cls.disable_servercount != cl.servercount && cl.refresh_prepped)
				SCR_EndLoadingPlaque();	// get rid of loading plaque
		}

		cl.sound_prepped = true;	// can start mixing ambient sounds

		// fire entity events
		CL_FireEntityEvents(&cl.frame);
		CL_CheckPredictionError();
	}
}
示例#18
0
/*
================
CL_ParseSnapshot

If the snapshot is parsed properly, it will be copied to
cl.snap and saved in cl.snapshots[].  If the snapshot is invalid
for any reason, no changes to the state will be made at all.
================
*/
void CL_ParseSnapshot( msg_t *msg )
{
	int          len;
	clSnapshot_t *old;
	clSnapshot_t newSnap;
	int          deltaNum;
	int          oldMessageNum;
	int          i, packetNum;

	// get the reliable sequence acknowledge number
	// NOTE: now sent with all server to client messages
	//clc.reliableAcknowledge = MSG_ReadLong( msg );

	// read in the new snapshot to a temporary buffer
	// we will only copy to cl.snap if it is valid
	Com_Memset( &newSnap, 0, sizeof( newSnap ) );

	// we will have read any new server commands in this
	// message before we got to svc_snapshot
	newSnap.serverCommandNum = clc.serverCommandSequence;

	newSnap.serverTime = MSG_ReadLong( msg );

	// if we were just unpaused, we can only *now* really let the
	// change come into effect or the client hangs.
	cl_paused->modified = 0;

	newSnap.messageNum = clc.serverMessageSequence;

	deltaNum = MSG_ReadByte( msg );

	if ( !deltaNum )
	{
		newSnap.deltaNum = -1;
	}
	else
	{
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
	}

	newSnap.snapFlags = MSG_ReadByte( msg );

	// If the frame is delta compressed from data that we
	// no longer have available, we must suck up the rest of
	// the frame, but not use it, then ask for a non-compressed
	// message
	if ( newSnap.deltaNum <= 0 )
	{
		newSnap.valid = qtrue; // uncompressed frame
		old = NULL;

		if ( clc.demorecording )
		{
			clc.demowaiting = qfalse; // we can start recording now
//          if(cl_autorecord->integer) {
//              Cvar_Set( "g_synchronousClients", "0" );
//          }
		}
		else
		{
			if ( cl_autorecord->integer /*&& Cvar_VariableValue( "g_synchronousClients") */ )
			{
				char    name[ 256 ];
				char    mapname[ MAX_QPATH ];
				char    *period;
				qtime_t time;

				Com_RealTime( &time );

				Q_strncpyz( mapname, cl.mapname, MAX_QPATH );

				for ( period = mapname; *period; period++ )
				{
					if ( *period == '.' )
					{
						*period = '\0';
						break;
					}
				}

				for ( period = mapname; *period; period++ )
				{
					if ( *period == '/' )
					{
						break;
					}
				}

				if ( *period )
				{
					period++;
				}

				Com_sprintf( name, sizeof( name ), "demos/%s_%04i-%02i-%02i_%02i%02i%02i.dm_%d", period,
				             1900 + time.tm_year, time.tm_mon + 1, time.tm_mday,
				             time.tm_hour, time.tm_min, time.tm_sec,
				             PROTOCOL_VERSION );

				CL_Record( name );
			}
		}
	}
	else
	{
		old = &cl.snapshots[ newSnap.deltaNum & PACKET_MASK ];

		if ( !old->valid )
		{
			// should never happen
			Com_Printf( "Delta from invalid frame (not supposed to happen!).\n" );
		}
		else if ( old->messageNum != newSnap.deltaNum )
		{
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_DPrintf( "Delta frame too old.\n" );
		}
		else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES - 128 )
		{
			Com_DPrintf( "Delta parseEntitiesNum too old.\n" );
		}
		else
		{
			newSnap.valid = qtrue; // valid delta parse
		}
	}

	// read areamask
	len = MSG_ReadByte( msg );

	if ( len > sizeof( newSnap.areamask ) )
	{
		Com_Error( ERR_DROP, "CL_ParseSnapshot: Invalid size %d for areamask.", len );
	}

	MSG_ReadData( msg, &newSnap.areamask, len );

	// read playerinfo
	SHOWNET( msg, "playerstate" );

	if ( old )
	{
		MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
	}
	else
	{
		MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
	}

	// read packet entities
	SHOWNET( msg, "packet entities" );
	CL_ParsePacketEntities( msg, old, &newSnap );

	// if not valid, dump the entire thing now that it has
	// been properly read
	if ( !newSnap.valid )
	{
		return;
	}

	// clear the valid flags of any snapshots between the last
	// received and this one, so if there was a dropped packet
	// it won't look like something valid to delta from next
	// time we wrap around in the buffer
	oldMessageNum = cl.snap.messageNum + 1;

	if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP )
	{
		oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
	}

	for ( ; oldMessageNum < newSnap.messageNum; oldMessageNum++ )
	{
		cl.snapshots[ oldMessageNum & PACKET_MASK ].valid = qfalse;
	}

	// copy to the current good spot
	cl.snap = newSnap;
	cl.snap.ping = 999;

	// calculate ping time
	for ( i = 0; i < PACKET_BACKUP; i++ )
	{
		packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;

		if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime )
		{
			cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
			break;
		}
	}

	// save the frame off in the backup array for later delta comparisons
	cl.snapshots[ cl.snap.messageNum & PACKET_MASK ] = cl.snap;

	if ( cl_shownet->integer == 3 )
	{
		Com_Printf( "   snapshot:%i  delta:%i  ping:%i\n", cl.snap.messageNum, cl.snap.deltaNum, cl.snap.ping );
	}

	cl.newSnapshots = qtrue;
}
示例#19
0
/*
================
CL_ParseSnapshot

If the snapshot is parsed properly, it will be copied to
cl.snap and saved in cl.snapshots[].  If the snapshot is invalid
for any reason, no changes to the state will be made at all.
================
*/
void CL_ParseSnapshot( msg_t *msg ) {
	int			len;
	clSnapshot_t	*old;
	clSnapshot_t	newSnap;
	int			deltaNum;
	int			oldMessageNum;
	int			i, packetNum;

	// get the reliable sequence acknowledge number
	// NOTE: now sent with all server to client messages
	//clc.reliableAcknowledge = MSG_ReadLong( msg );

	// read in the new snapshot to a temporary buffer
	// we will only copy to cl.snap if it is valid
	Com_Memset (&newSnap, 0, sizeof(newSnap));

	// we will have read any new server commands in this
	// message before we got to svc_snapshot
	newSnap.serverCommandNum = clc.serverCommandSequence;

	newSnap.serverTime = MSG_ReadLong( msg );

	// if we were just unpaused, we can only *now* really let the
	// change come into effect or the client hangs.
	cl_paused->modified = qfalse;

	newSnap.messageNum = clc.serverMessageSequence;

	deltaNum = MSG_ReadByte( msg );
	if ( !deltaNum ) {
		newSnap.deltaNum = -1;
	} else {
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
	}
	newSnap.snapFlags = MSG_ReadByte( msg );

	// If the frame is delta compressed from data that we
	// no longer have available, we must suck up the rest of
	// the frame, but not use it, then ask for a non-compressed
	// message 
	if ( newSnap.deltaNum <= 0 ) {
		newSnap.valid = qtrue;		// uncompressed frame
		old = NULL;
		clc.demowaiting = qfalse;	// we can start recording now
	} else {
		old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
		if ( !old->valid ) {
			// should never happen
			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
		} else if ( old->messageNum != newSnap.deltaNum ) {
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_Printf ("Delta frame too old.\n");
		} else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
			Com_DPrintf ("Delta parseEntitiesNum too old.\n");
		} else {
			newSnap.valid = qtrue;	// valid delta parse
		}
	}

	// read areamask
	len = MSG_ReadByte( msg );

	if((unsigned)len > sizeof(newSnap.areamask))
	{
		Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask", len);
		return;
	}

	MSG_ReadData( msg, &newSnap.areamask, len);

	// read playerinfo
	SHOWNET( msg, "playerstate" );
	if ( old ) {
		MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
		if (newSnap.ps.m_iVehicleNum)
		{ //this means we must have written our vehicle's ps too
			MSG_ReadDeltaPlayerstate( msg, &old->vps, &newSnap.vps, qtrue );
		}
	} else {
		MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
		if (newSnap.ps.m_iVehicleNum)
		{ //this means we must have written our vehicle's ps too
			MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.vps, qtrue );			
		}
	}

	// read packet entities
	SHOWNET( msg, "packet entities" );
	CL_ParsePacketEntities( msg, old, &newSnap );

	// if not valid, dump the entire thing now that it has
	// been properly read
	if ( !newSnap.valid ) {
		return;
	}

	// clear the valid flags of any snapshots between the last
	// received and this one, so if there was a dropped packet
	// it won't look like something valid to delta from next
	// time we wrap around in the buffer
	oldMessageNum = cl.snap.messageNum + 1;

	if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
		oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
	}
	for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
		cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
	}

	// copy to the current good spot
	cl.snap = newSnap;
	cl.snap.ping = 999;
	// calculate ping time
	for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
		packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
		if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {
			cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
			break;
		}
	}
	// save the frame off in the backup array for later delta comparisons
	cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;

	if (cl_shownet->integer == 3) {
		Com_Printf( "   snapshot:%i  delta:%i  ping:%i\n", cl.snap.messageNum,
		cl.snap.deltaNum, cl.snap.ping );
	}

	cl.newSnapshots = qtrue;
}
示例#20
0
/*
=====================
CL_ParseVoip

A VoIP message has been received from the server
=====================
*/
static
void CL_ParseVoip( msg_t *msg )
{
	static short decoded[ 4096 ]; // !!! FIXME: don't hardcode.

	const int    sender = MSG_ReadShort( msg );
	const int    generation = MSG_ReadByte( msg );
	const int    sequence = MSG_ReadLong( msg );
	const int    frames = MSG_ReadByte( msg );
	const int    packetsize = MSG_ReadShort( msg );
	const int    flags = MSG_ReadBits( msg, VOIP_FLAGCNT );
	char         encoded[ 1024 ];
	int          seqdiff = sequence - clc.voipIncomingSequence[ sender ];
	int          written = 0;
	int          i;

	Com_DPrintf( "VoIP: %d-byte packet from client %d\n", packetsize, sender );

	if ( sender < 0 )
	{
		return; // short/invalid packet, bail.
	}
	else if ( generation < 0 )
	{
		return; // short/invalid packet, bail.
	}
	else if ( sequence < 0 )
	{
		return; // short/invalid packet, bail.
	}
	else if ( frames < 0 )
	{
		return; // short/invalid packet, bail.
	}
	else if ( packetsize < 0 )
	{
		return; // short/invalid packet, bail.
	}

	if ( packetsize > sizeof( encoded ) )  // overlarge packet?
	{
		int bytesleft = packetsize;

		while ( bytesleft )
		{
			int br = bytesleft;

			if ( br > sizeof( encoded ) )
			{
				br = sizeof( encoded );
			}

			MSG_ReadData( msg, encoded, br );
			bytesleft -= br;
		}

		return; // overlarge packet, bail.
	}

	if ( !clc.speexInitialized )
	{
		MSG_ReadData( msg, encoded, packetsize );  // skip payload.
		return; // can't handle VoIP without libspeex!
	}
	else if ( sender >= MAX_CLIENTS )
	{
		MSG_ReadData( msg, encoded, packetsize );  // skip payload.
		return; // bogus sender.
	}
	else if ( CL_ShouldIgnoreVoipSender( sender ) )
	{
		MSG_ReadData( msg, encoded, packetsize );  // skip payload.
		return; // Channel is muted, bail.
	}

	// !!! FIXME: make sure data is narrowband? Does decoder handle this?

	Com_DPrintf( "VoIP: packet accepted!\n" );

	// This is a new "generation" ... a new recording started, reset the bits.
	if ( generation != clc.voipIncomingGeneration[ sender ] )
	{
		Com_DPrintf( "VoIP: new generation %d!\n", generation );
		speex_bits_reset( &clc.speexDecoderBits[ sender ] );
		clc.voipIncomingGeneration[ sender ] = generation;
		seqdiff = 0;
	}
	else if ( seqdiff < 0 ) // we're ahead of the sequence?!
	{
		// This shouldn't happen unless the packet is corrupted or something.
		Com_DPrintf( "VoIP: misordered sequence! %d < %d!\n",
		             sequence, clc.voipIncomingSequence[ sender ] );
		// reset the bits just in case.
		speex_bits_reset( &clc.speexDecoderBits[ sender ] );
		seqdiff = 0;
	}
	else if ( seqdiff > 100 ) // more than 2 seconds of audio dropped?
	{
		// just start over.
		Com_DPrintf( "VoIP: Dropped way too many (%d) frames from client #%d\n",
		             seqdiff, sender );
		speex_bits_reset( &clc.speexDecoderBits[ sender ] );
		seqdiff = 0;
	}

	if ( seqdiff != 0 )
	{
		Com_DPrintf( "VoIP: Dropped %d frames from client #%d\n",
		             seqdiff, sender );

		// tell speex that we're missing frames...
		for ( i = 0; i < seqdiff; i++ )
		{
			assert( ( written + clc.speexFrameSize ) * 2 < sizeof( decoded ) );
			speex_decode_int( clc.speexDecoder[ sender ], NULL, decoded + written );
			written += clc.speexFrameSize;
		}
	}

	for ( i = 0; i < frames; i++ )
	{
		const int len = MSG_ReadByte( msg );

		if ( len < 0 )
		{
			Com_DPrintf( "VoIP: Short packet!\n" );
			break;
		}

		MSG_ReadData( msg, encoded, len );

		// shouldn't happen, but just in case...
		if ( ( written + clc.speexFrameSize ) * 2 > sizeof( decoded ) )
		{
			Com_DPrintf( "VoIP: playback %d bytes, %d samples, %d frames\n",
			             written * 2, written, i );

			CL_PlayVoip( sender, written, ( const byte * ) decoded, flags );
			written = 0;
		}

		speex_bits_read_from( &clc.speexDecoderBits[ sender ], encoded, len );
		speex_decode_int( clc.speexDecoder[ sender ],
		                  &clc.speexDecoderBits[ sender ], decoded + written );

#if 0
		static FILE *encio = NULL;

		if ( encio == NULL ) { encio = fopen( "voip-incoming-encoded.bin", "wb" ); }

		if ( encio != NULL ) { fwrite( encoded, len, 1, encio ); fflush( encio ); }

		static FILE *decio = NULL;

		if ( decio == NULL ) { decio = fopen( "voip-incoming-decoded.bin", "wb" ); }

		if ( decio != NULL ) { fwrite( decoded + written, clc.speexFrameSize * 2, 1, decio ); fflush( decio ); }

#endif

		written += clc.speexFrameSize;
	}

	Com_DPrintf( "VoIP: playback %d bytes, %d samples, %d frames\n",
	             written * 2, written, i );

	if ( written > 0 )
	{
		CL_PlayVoip( sender, written, ( const byte * ) decoded, flags );
	}

	clc.voipIncomingSequence[ sender ] = sequence + frames;
}
示例#21
0
void CL_ParseRMG ( msg_t* msg )
{
	clc.rmgHeightMapSize = (unsigned short)MSG_ReadShort ( msg );
	if ( !clc.rmgHeightMapSize )
	{
		return;
	}

	z_stream zdata;
	int		 size;
	unsigned char heightmap1[15000];

	if ( MSG_ReadBits ( msg, 1 ) )
	{
		// Read the heightmap
		memset(&zdata, 0, sizeof(z_stream));
		inflateInit ( &zdata/*, Z_SYNC_FLUSH*/ );

		MSG_ReadData ( msg, heightmap1, clc.rmgHeightMapSize );

		zdata.next_in = heightmap1;
		zdata.avail_in = clc.rmgHeightMapSize;
		zdata.next_out = (unsigned char*)clc.rmgHeightMap;
		zdata.avail_out = MAX_HEIGHTMAP_SIZE;
		inflate (&zdata,Z_SYNC_FLUSH );

		clc.rmgHeightMapSize = zdata.total_out;

		inflateEnd(&zdata);
	}
	else
	{
		MSG_ReadData ( msg, (unsigned char*)clc.rmgHeightMap, clc.rmgHeightMapSize );
	}

	size = (unsigned short)MSG_ReadShort ( msg );

	if ( MSG_ReadBits ( msg, 1 ) )
	{	
		// Read the flatten map
		memset(&zdata, 0, sizeof(z_stream));
		inflateInit ( &zdata/*, Z_SYNC_FLUSH*/ );

		MSG_ReadData ( msg, heightmap1, size );

		zdata.next_in = heightmap1;
		zdata.avail_in = clc.rmgHeightMapSize;
		zdata.next_out = (unsigned char*)clc.rmgFlattenMap;
		zdata.avail_out = MAX_HEIGHTMAP_SIZE;
		inflate (&zdata, Z_SYNC_FLUSH);
		inflateEnd(&zdata);
	}
	else
	{
		MSG_ReadData ( msg, (unsigned char*)clc.rmgFlattenMap, size );
	}

	// Read the seed		
	clc.rmgSeed = MSG_ReadLong ( msg );

	CL_ParseAutomapSymbols ( msg );
}
示例#22
0
qboolean demoCutParseSnapshot(msg_t *msg, clientConnection_t *clcCut, clientActive_t *clCut) {
	int len;
	clSnapshot_t *oldSnap;
	clSnapshot_t newSnap;
	int deltaNum;
	int oldMessageNum;
	int i, packetNum;
	Com_Memset(&newSnap, 0, sizeof(newSnap));
	newSnap.serverCommandNum = clcCut->serverCommandSequence;
	newSnap.serverTime = MSG_ReadLong(msg);
	cl_paused->modified = qfalse;
	newSnap.messageNum = clcCut->serverMessageSequence;
	deltaNum = MSG_ReadByte(msg);
	newSnap.snapFlags = MSG_ReadByte(msg);
	if (!deltaNum) {
		newSnap.deltaNum = -1;
		newSnap.valid = qtrue;		// uncompressed frame
		oldSnap = NULL;
	} else {
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
		oldSnap = &clCut->snapshots[newSnap.deltaNum & PACKET_MASK];
		if (!oldSnap->valid) {
			// should never happen
			Com_Printf("Delta from invalid frame (not supposed to happen!).\n");
		} else if (oldSnap->messageNum != newSnap.deltaNum) {
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_Printf("Delta frame too old.\n");
		} else if (clCut->parseEntitiesNum - oldSnap->parseEntitiesNum > MAX_PARSE_ENTITIES-128) {
			Com_DPrintf("Delta parseEntitiesNum too old.\n");
		} else {
			newSnap.valid = qtrue;	// valid delta parse
		}
	}
	// read areamask
	len = MSG_ReadByte(msg);
	if(len > sizeof(newSnap.areamask)) {
		Com_Printf("demoCutParseSnapshot: Invalid size %d for areamask", len);
		return qfalse;
	}
	MSG_ReadData(msg, &newSnap.areamask, len);
	// read playerinfo
	MSG_ReadDeltaPlayerstate(msg, oldSnap ? &oldSnap->ps : NULL, &newSnap.ps);
	if(newSnap.ps.m_iVehicleNum)
		MSG_ReadDeltaPlayerstate(msg, oldSnap ? &oldSnap->vps : NULL, &newSnap.vps, qtrue);
	// read packet entities
	demoCutParsePacketEntities(msg, oldSnap, &newSnap, clCut);
	// if not valid, dump the entire thing now that it has
	// been properly read
	if (!newSnap.valid) {
		return qtrue;
	}
	// clear the valid flags of any snapshots between the last
	// received and this one, so if there was a dropped packet
	// it won't look like something valid to delta from next
	// time we wrap around in the buffer
	oldMessageNum = clCut->snap.messageNum + 1;
	if (newSnap.messageNum - oldMessageNum >= PACKET_BACKUP) {
		oldMessageNum = newSnap.messageNum - (PACKET_BACKUP - 1);
	}
	for (;oldMessageNum < newSnap.messageNum; oldMessageNum++) {
		clCut->snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
	}
	// copy to the current good spot
	clCut->snap = newSnap;
	clCut->snap.ping = 999;
	// calculate ping time
	for (i = 0; i < PACKET_BACKUP; i++) {
		packetNum = (clcCut->netchan.outgoingSequence-1-i) & PACKET_MASK;
		if (clCut->snap.ps.commandTime >= clCut->outPackets[packetNum].p_serverTime) {
			clCut->snap.ping = cls.realtime - clCut->outPackets[packetNum].p_realtime;
			break;
		}
	}
	// save the frame off in the backup array for later delta comparisons
	clCut->snapshots[clCut->snap.messageNum & PACKET_MASK] = clCut->snap;
	clCut->newSnapshots = qtrue;
	return qtrue;
}
示例#23
0
/*
================
CL_ParseSnapshot

If the snapshot is parsed properly, it will be copied to
cl.snap and saved in cl.snapshots[].  If the snapshot is invalid
for any reason, no changes to the state will be made at all.
================
*/
void CL_ParseSnapshot( msg_t *msg ) {
	int			len;
	clSnapshot_t	*old;
	clSnapshot_t	newSnap;
	sharedPlayerState_t *newPS, *oldPS;
	int			deltaNum;
	int			oldMessageNum;
	int			i, packetNum;

	if ( !cgvm ) {
		Com_Error( ERR_DROP, "Received unexpected snapshot" );
	}

	if ( !cl.cgamePlayerStateSize || !cl.cgameEntityStateSize ) {
		Com_Error( ERR_DROP, "cgame needs to call trap_SetNetFields" );
	}

	// get the reliable sequence acknowledge number
	// NOTE: now sent with all server to client messages
	//clc.reliableAcknowledge = MSG_ReadLong( msg );

	// read in the new snapshot to a temporary buffer
	// we will only copy to cl.snap if it is valid
	Com_Memset (&newSnap, 0, sizeof(newSnap));

	// we will have read any new server commands in this
	// message before we got to svc_snapshot
	newSnap.serverCommandNum = clc.serverCommandSequence;

	newSnap.serverTime = MSG_ReadLong( msg );

	// if we were just unpaused, we can only *now* really let the
	// change come into effect or the client hangs.
	cl_paused->modified = 0;

	newSnap.messageNum = clc.serverMessageSequence;

	deltaNum = MSG_ReadByte( msg );
	if ( !deltaNum ) {
		newSnap.deltaNum = -1;
	} else {
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
	}
	newSnap.snapFlags = MSG_ReadByte( msg );

	// If the frame is delta compressed from data that we
	// no longer have available, we must suck up the rest of
	// the frame, but not use it, then ask for a non-compressed
	// message 
	if ( newSnap.deltaNum <= 0 ) {
		newSnap.valid = qtrue;		// uncompressed frame
		old = NULL;
		clc.demowaiting = qfalse;	// we can start recording now
	} else {
		old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
		if ( !old->valid ) {
			// should never happen
			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
		} else if ( old->messageNum != newSnap.deltaNum ) {
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_Printf ("Delta frame too old.\n");
		} else if ( cl.parseEntitiesNum - old->parseEntitiesNum > cl.parseEntities.maxElements - MAX_SNAPSHOT_ENTITIES * CL_MAX_SPLITVIEW ) {
			Com_Printf ("Delta parseEntitiesNum too old.\n");
		} else {
			newSnap.valid = qtrue;	// valid delta parse
		}
	}

	DA_Clear( &cl.tempSnapshotPS );

	// read playerinfo
	SHOWNET( msg, "playerstate" );

	newSnap.numPSs = MSG_ReadByte( msg );
	if (newSnap.numPSs > MAX_SPLITVIEW) {
		Com_DPrintf(S_COLOR_YELLOW "Warning: Got numPSs as %d (max=%d)\n", newSnap.numPSs, MAX_SPLITVIEW);
		newSnap.numPSs = MAX_SPLITVIEW;
	}

	for (i = 0; i < MAX_SPLITVIEW; i++) {
		newSnap.localPlayerIndex[i] = MSG_ReadByte( msg );
		newSnap.playerNums[i] = MSG_ReadByte( msg );

		// -1 gets converted to 255 should be set to -1 (and so should all invalid values)
		if ( newSnap.localPlayerIndex[i] >= newSnap.numPSs || newSnap.playerNums[i] >= MAX_CLIENTS ) {
			newSnap.localPlayerIndex[i] = -1;
			newSnap.playerNums[i] = -1;
		}

		// read areamask
		len = MSG_ReadByte( msg );

		if(len > sizeof(newSnap.areamask[0]))
		{
			Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask", len);
			return;
		}

		MSG_ReadData( msg, &newSnap.areamask[i], len);
	}

	for (i = 0; i < MAX_SPLITVIEW; i++) {
		// Read player states
		if (newSnap.localPlayerIndex[i] != -1) {
			newPS = (sharedPlayerState_t *) DA_ElementPointer( cl.tempSnapshotPS, newSnap.localPlayerIndex[i] );

			if ( old && old->valid && old->localPlayerIndex[i] != -1 ) {
				oldPS = (sharedPlayerState_t *) DA_ElementPointer( old->playerStates, old->localPlayerIndex[i] );

				MSG_ReadDeltaPlayerstate( msg, oldPS, newPS, newSnap.playerNums[i] );
			} else {
				MSG_ReadDeltaPlayerstate( msg, NULL, newPS, newSnap.playerNums[i] );
			}
		}

		// Server added or removed local player
		if ( old && old->playerNums[i] != newSnap.playerNums[i] ) {
			CL_LocalPlayerRemoved( i );

			if ( newSnap.playerNums[i] != -1 ) {
				CL_LocalPlayerAdded( i, newSnap.playerNums[i] );
			}
		}
	}

	// read packet entities
	SHOWNET( msg, "packet entities" );
	CL_ParsePacketEntities( msg, old, &newSnap );

	// if not valid, dump the entire thing now that it has
	// been properly read
	if ( !newSnap.valid ) {
		return;
	}

	// clear the valid flags of any snapshots between the last
	// received and this one, so if there was a dropped packet
	// it won't look like something valid to delta from next
	// time we wrap around in the buffer
	oldMessageNum = cl.snap.messageNum + 1;

	if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
		oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
	}
	for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
		cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
	}

	// copy player states from temp to snapshot
	DA_Copy( cl.tempSnapshotPS, &cl.snapshots[newSnap.messageNum & PACKET_MASK].playerStates );
	newSnap.playerStates = cl.snapshots[newSnap.messageNum & PACKET_MASK].playerStates;

	// copy to the current good spot
	cl.snap = newSnap;
	cl.snap.ping = 999;
	// calculate ping time
	for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
		packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
		newPS = (sharedPlayerState_t *) DA_ElementPointer( cl.snap.playerStates, 0 );
		if ( newPS->commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {
			cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
			break;
		}
	}
	// save the frame off in the backup array for later delta comparisons
	cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;

	if (cl_shownet->integer == 3) {
		Com_Printf( "   snapshot:%i  delta:%i  ping:%i\n", cl.snap.messageNum,
		cl.snap.deltaNum, cl.snap.ping );
	}

	cl.newSnapshots = qtrue;
}