void BlobNetworkBypass_CustomDemoDataCallback( uint8 *pData, size_t iSize )
{
	// FIXME: need a version number!

	uint8 *pParse = pData;
	int iMaxIndex = LittleDWord( *(int *)pParse );
	pParse += sizeof( int );

	int iBitMax = (iMaxIndex / BITS_PER_INT) + 1;

	Assert( iSize == (sizeof( int ) + sizeof( float ) + sizeof( int ) + sizeof( int ) + (sizeof( int ) * iBitMax) +
			iMaxIndex*( sizeof( Vector ) + sizeof( float ) + sizeof( Vector ) )) );
	
	g_pBlobNetworkBypass->fTimeDataUpdated = *(float *)pParse;
	pParse += sizeof( float );

	g_pBlobNetworkBypass->iHighestIndexUsed = LittleDWord( *(int *)pParse );
	pParse += sizeof( int );

	g_pBlobNetworkBypass->iNumParticlesAllocated = LittleDWord( *(int *)pParse );
	pParse += sizeof( int );

	int *pIntParser = (int *)&g_pBlobNetworkBypass->bCurrentlyInUse;
	for( int i = 0; i != iBitMax; ++i )
	{
		//read and convert the bitfield integers
		*pIntParser = LittleDWord( *(int *)pParse );
		pParse += sizeof( int );
		++pIntParser;
	}

	//read positions
	memcpy( g_pBlobNetworkBypass->vParticlePositions, pParse, sizeof( Vector ) * iMaxIndex );
	pParse += sizeof( Vector ) * iMaxIndex;

	//read radii
	memcpy( g_pBlobNetworkBypass->vParticleRadii, pParse, sizeof( float ) * iMaxIndex );
	pParse += sizeof( float ) * iMaxIndex;

	//read closest surface direction
	memcpy( g_pBlobNetworkBypass->vParticleClosestSurfDir, pParse, sizeof( Vector ) * iMaxIndex );
	pParse += sizeof( Vector ) * iMaxIndex;

	g_pBlobNetworkBypass->bDataUpdated = true;

	Assert( pParse == (pData + iSize) );
}
예제 #2
0
uint32 GenerateSoundEntryHash(char const *pSoundEntry)
{
	// First we need to convert the sound entry to lowercase before we calculate the hash
	int nSoundEntryLength = strlen(pSoundEntry);
	char *pSoundEntryLowerCase = (char *)stackalloc(nSoundEntryLength + 1);

	for (int nIndex = 0; nIndex < nSoundEntryLength; nIndex++)
		pSoundEntryLowerCase[nIndex] = tolower(pSoundEntry[nIndex]);

	// Second we need to calculate the hash using the algorithm reconstructed from CS:GO
	const uint32 nMagicNumber = 0x5bd1e995;

	uint32 nSoundHash = SOUND_ENTRY_HASH_SEED ^ nSoundEntryLength;

	unsigned char *pData = (unsigned char *)pSoundEntryLowerCase;

	while (nSoundEntryLength >= 4)
	{
		uint32 nLittleDWord = LittleDWord(*(uint32 *)pData);

		nLittleDWord *= nMagicNumber;
		nLittleDWord ^= nLittleDWord >> 24;
		nLittleDWord *= nMagicNumber;

		nSoundHash *= nMagicNumber;
		nSoundHash ^= nLittleDWord;

		pData += 4;
		nSoundEntryLength -= 4;
	}

	switch (nSoundEntryLength)
	{
		case 3: nSoundHash ^= pData[2] << 16;
		case 2: nSoundHash ^= pData[1] << 8;
		case 1: nSoundHash ^= pData[0];
			nSoundHash *= nMagicNumber;
	};

	nSoundHash ^= nSoundHash >> 13;
	nSoundHash *= nMagicNumber;
	nSoundHash ^= nSoundHash >> 15;

	return nSoundHash;
}
예제 #3
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : cmd - 
//			dt - 
//			frame - 
//-----------------------------------------------------------------------------
void CToolDemoFile::ReadCmdHeader( unsigned char& cmd, int& tick )
{
	Assert( m_hDemoFile != FILESYSTEM_INVALID_HANDLE );

	// Read the command
	int r = g_pFileSystem->Read ( &cmd, sizeof(byte), m_hDemoFile );
	
	if ( r <=0 )
	{
		Warning("Missing end tag in demo file.\n");
		cmd = dem_stop;
		return;
	}

	Assert( cmd >= 1 && cmd <= dem_lastcmd );

	// Read the timestamp
	g_pFileSystem->Read ( &tick, sizeof(int), m_hDemoFile );
	
	tick = LittleDWord( tick );
}
예제 #4
0
//-----------------------------------------------------------------------------
// Purpose: Receives incoming network data
//-----------------------------------------------------------------------------
void CSpaceWarServer::ReceiveNetworkData()
{
	char *pchRecvBuf = NULL;
	uint32 cubMsgSize;
	CSteamID steamIDRemote;
	while ( SteamGameServerNetworking()->IsP2PPacketAvailable( &cubMsgSize ) )
	{
		// free any previous receive buffer
		if ( pchRecvBuf )
			free( pchRecvBuf );

		// alloc a new receive buffer of the right size
		pchRecvBuf = (char *)malloc( cubMsgSize );

		// see if there is any data waiting on the socket
		if ( !SteamGameServerNetworking()->ReadP2PPacket( pchRecvBuf, cubMsgSize, &cubMsgSize, &steamIDRemote ) )
			break;

		if ( cubMsgSize < sizeof( DWORD ) )
		{
			OutputDebugString( "Got garbage on server socket, too short\n" );
			continue;
		}

		EMessage eMsg = (EMessage)LittleDWord( *(DWORD*)pchRecvBuf );
		switch ( eMsg )
		{
		case k_EMsgClientInitiateConnection:
			{
				// We always let clients do this without even checking for room on the server since we reserve that for 
				// the authentication phase of the connection which comes next
				MsgServerSendInfo_t msg;
				msg.SetSteamIDServer( SteamGameServer()->GetSteamID().ConvertToUint64() );
#ifdef USE_GS_AUTH_API
				// You can only make use of VAC when using the Steam authentication system
				msg.SetSecure( SteamGameServer()->BSecure() );
#endif
				msg.SetServerName( m_sServerName.c_str() );
				SteamGameServerNetworking()->SendP2PPacket( steamIDRemote, &msg, sizeof( MsgServerSendInfo_t ), k_EP2PSendReliable );
			}
			break;
		case k_EMsgClientBeginAuthentication:
			{
				if ( cubMsgSize != sizeof( MsgClientBeginAuthentication_t ) )
				{
					OutputDebugString( "Bad connection attempt msg\n" );
					continue;
				}
				MsgClientBeginAuthentication_t *pMsg = (MsgClientBeginAuthentication_t*)pchRecvBuf;
#ifdef USE_GS_AUTH_API
				OnClientBeginAuthentication( steamIDRemote, (void*)pMsg->GetTokenPtr(), pMsg->GetTokenLen() );
#else
				OnClientBeginAuthentication( steamIDRemote, 0 );
#endif
			}
			break;
		case k_EMsgClientSendLocalUpdate:
			{
				if ( cubMsgSize != sizeof( MsgClientSendLocalUpdate_t ) )
				{
					OutputDebugString( "Bad client update msg\n" );
					continue;
				}

				// Find the connection that should exist for this users address
				bool bFound = false;
				for( uint32 i=0; i<MAX_PLAYERS_PER_SERVER; ++i )
				{
					if ( m_rgClientData[i].m_SteamIDUser == steamIDRemote ) 
					{
						bFound = true;
						MsgClientSendLocalUpdate_t *pMsg = (MsgClientSendLocalUpdate_t*)pchRecvBuf;
						OnReceiveClientUpdateData( i, pMsg->AccessUpdateData() );
						break;
					}
				}
				if ( !bFound )
					OutputDebugString( "Got a client data update, but couldn't find a matching client\n" );
			}
			break;
		case k_EMsgClientPing:
			{
				// send back a response
				MsgServerPingResponse_t msg;
				SteamGameServerNetworking()->SendP2PPacket( steamIDRemote, &msg, sizeof( msg ), k_EP2PSendUnreliable );
			}
			break;
		case k_EMsgClientLeavingServer:
			{
				if ( cubMsgSize != sizeof( MsgClientLeavingServer_t ) )
				{
					OutputDebugString( "Bad leaving server msg\n" );
					continue;
				}
				// Find the connection that should exist for this users address
				bool bFound = false;
				for( uint32 i=0; i<MAX_PLAYERS_PER_SERVER; ++i )
				{
					if ( m_rgClientData[i].m_SteamIDUser == steamIDRemote )
					{
						bFound = true;
						RemovePlayerFromServer( i );
						break;
					}

					// Also check for pending connections that may match
					if ( m_rgPendingClientData[i].m_SteamIDUser == steamIDRemote )
					{
	#ifdef USE_GS_AUTH_API
						// Tell the GS the user is leaving the server
						SteamGameServer()->SendUserDisconnect( m_rgPendingClientData[i].m_SteamIDUser );
	#endif
						// Clear our data on the user
						memset( &m_rgPendingClientData[i], 0 , sizeof( ClientConnectionData_t ) );
						break;
					}
				}
				if ( !bFound )
					OutputDebugString( "Got a client leaving server msg, but couldn't find a matching client\n" );
			}
		default:
			char rgch[128];
			sprintf_safe( rgch, "Invalid message %x\n", eMsg );
			rgch[ sizeof(rgch) - 1 ] = 0;
			OutputDebugString( rgch );
		}
	}

	if ( pchRecvBuf )
		free( pchRecvBuf );
}
void CBlobParticleNetworkBypassAutoGame::PreRender( void )
{
	if( engine->IsRecordingDemo() && g_pBlobNetworkBypass->bDataUpdated )
	{
		//record the update, TODO: compress the data by omitting the holes

		int iMaxIndex = MAX(g_pBlobNetworkBypass->iHighestIndexUsed, m_iOldHighestIndexUsed);
		int iBitMax = (iMaxIndex / BITS_PER_INT) + 1;

		size_t iDataSize = sizeof( int ) + sizeof( float ) + sizeof( int ) + sizeof( int ) + (sizeof( int ) * iBitMax) +
							iMaxIndex*( sizeof( Vector ) + sizeof( float ) + sizeof( Vector ) );
		uint8 *pData = new uint8 [iDataSize];
		uint8 *pWrite = pData;

		//let the receiver know how much of each array to expect
		*(int *)pWrite = LittleDWord( iMaxIndex );
		pWrite += sizeof( int );

		//write the update timestamp
		*(float *)pWrite = g_pBlobNetworkBypass->fTimeDataUpdated;
		pWrite += sizeof( float );

		//record usage information, also helps us effectively compress the subsequent data by omitting the holes.
		*(int *)pWrite = LittleDWord( g_pBlobNetworkBypass->iHighestIndexUsed );
		pWrite += sizeof( int );

		*(int *)pWrite = LittleDWord( g_pBlobNetworkBypass->iNumParticlesAllocated );
		pWrite += sizeof( int );

		int *pIntParser = (int *)&g_pBlobNetworkBypass->bCurrentlyInUse;
		for( int i = 0; i != iBitMax; ++i )
		{
			//convert and write the bitfield integers
			*(int *)pWrite = LittleDWord( *pIntParser );
			pWrite += sizeof( int );
			++pIntParser;
		}

		//write positions
		memcpy( pWrite, g_pBlobNetworkBypass->vParticlePositions, sizeof( Vector ) * iMaxIndex );
		pWrite += sizeof( Vector ) * iMaxIndex;

		//write radii
		memcpy( pWrite, g_pBlobNetworkBypass->vParticleRadii, sizeof( float ) * iMaxIndex );
		pWrite += sizeof( float ) * iMaxIndex;

		//write closest surface direction
		memcpy( pWrite, g_pBlobNetworkBypass->vParticleClosestSurfDir, sizeof( Vector ) * iMaxIndex );
		pWrite += sizeof( Vector ) * iMaxIndex;

		engine->RecordDemoCustomData( BlobNetworkBypass_CustomDemoDataCallback, pData, iDataSize );

		Assert( pWrite == (pData + iDataSize) );

		delete []pData;
	}

	//invalidate interpolation on freed indices, do a quick update for brand new indices
	{
		//operate on smaller chunks based on the assumption that LARGE portions of the end of the bitvecs are empty
		CBitVec<BITS_PER_INT> *pCurrentlyInUse = (CBitVec<BITS_PER_INT> *)&g_pBlobNetworkBypass->bCurrentlyInUse;
		CBitVec<BITS_PER_INT> *pOldInUse = (CBitVec<BITS_PER_INT> *)&m_bOldInUse;
		int iStop = (MAX(g_pBlobNetworkBypass->iHighestIndexUsed, m_iOldHighestIndexUsed) / BITS_PER_INT) + 1;
		int iBaseIndex = 0;

		//float fNewIndicesUpdateTime = g_pBlobNetworkBypass->bPositionsUpdated ? g_pBlobNetworkBypass->fTimeDataUpdated : gpGlobals->curtime;

		for( int i = 0; i != iStop; ++i )
		{
			CBitVec<BITS_PER_INT> bInUseXOR;
			pCurrentlyInUse->Xor( *pOldInUse, &bInUseXOR ); //find bits that changed
			
			int j = 0;
			while( (j = bInUseXOR.FindNextSetBit( j )) != -1 )
			{
				int iChangedUsageIndex = iBaseIndex + j;
				
				if( pOldInUse->IsBitSet( iChangedUsageIndex ) )
				{
					//index no longer used
					g_BlobParticleInterpolation.vInterpolatedPositions[iChangedUsageIndex] = vec3_origin;
					s_PositionInterpolators[iChangedUsageIndex].ClearHistory();
					g_BlobParticleInterpolation.vInterpolatedRadii[iChangedUsageIndex] = 1.0f;
					s_RadiusInterpolators[iChangedUsageIndex].ClearHistory();
					g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iChangedUsageIndex] = vec3_origin;
					s_ClosestSurfDirInterpolators[iChangedUsageIndex].ClearHistory();
				}
				else
				{
					//index just started being used. Assume we got an out of band update to the position
					g_BlobParticleInterpolation.vInterpolatedPositions[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticlePositions[iChangedUsageIndex];
					s_PositionInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
					g_BlobParticleInterpolation.vInterpolatedRadii[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticleRadii[iChangedUsageIndex];
					s_RadiusInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
					g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticleClosestSurfDir[iChangedUsageIndex];
					s_ClosestSurfDirInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
					//s_PositionInterpolators[iChangedUsageIndex].NoteChanged( gpGlobals->curtime, fNewIndicesUpdateTime, true );
				}

				++j;
				if( j == BITS_PER_INT )
					break;
			}
			iBaseIndex += BITS_PER_INT;
			++pCurrentlyInUse;
			++pOldInUse;
		}

		memcpy( &m_bOldInUse, &g_pBlobNetworkBypass->bCurrentlyInUse, sizeof( m_bOldInUse ) );
		m_iOldHighestIndexUsed = g_pBlobNetworkBypass->iHighestIndexUsed;
	}

	if( g_pBlobNetworkBypass->iHighestIndexUsed == 0 )
		return;

	static ConVarRef cl_interpREF( "cl_interp" );
	//now do the interpolation of positions still in use
	{
		float fInterpTime = gpGlobals->curtime - cl_interpREF.GetFloat();

		CBitVec<BITS_PER_INT> *pIntParser = (CBitVec<BITS_PER_INT> *)&g_pBlobNetworkBypass->bCurrentlyInUse;
		int iStop = (g_pBlobNetworkBypass->iHighestIndexUsed / BITS_PER_INT) + 1;
		int iBaseIndex = 0;
		for( int i = 0; i != iStop; ++i )
		{
			int j = 0;
			while( (j = pIntParser->FindNextSetBit( j )) != -1 )
			{
				int iUpdateIndex = iBaseIndex + j;

				if( g_pBlobNetworkBypass->bDataUpdated )
				{
					g_BlobParticleInterpolation.vInterpolatedPositions[iUpdateIndex] = g_pBlobNetworkBypass->vParticlePositions[iUpdateIndex];
					s_PositionInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
					g_BlobParticleInterpolation.vInterpolatedRadii[iUpdateIndex] = g_pBlobNetworkBypass->vParticleRadii[iUpdateIndex];
					s_RadiusInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
					g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iUpdateIndex] = g_pBlobNetworkBypass->vParticleClosestSurfDir[iUpdateIndex];
					s_ClosestSurfDirInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
					//s_PositionInterpolators[iUpdateIndex].AddToHead( gpGlobals->curtime, &g_pBlobNetworkBypass->vParticlePositions[iUpdateIndex], false );
				}

				s_PositionInterpolators[iUpdateIndex].Interpolate( fInterpTime );
				s_RadiusInterpolators[iUpdateIndex].Interpolate( fInterpTime );
				s_ClosestSurfDirInterpolators[iUpdateIndex].Interpolate( fInterpTime );

				++j;
				if( j == BITS_PER_INT )
					break;
			}
			iBaseIndex += BITS_PER_INT;
			++pIntParser;
		}

		g_pBlobNetworkBypass->bDataUpdated = false;
	}
}