/*
========================
idCommonLocal::NetReadUsercmds
========================
*/
void idCommonLocal::NetReadUsercmds( int clientNum, idBitMsg& msg )
{
	if( clientNum == -1 )
	{
		idLib::Warning( "NetReadUsercmds: Trying to read commands from invalid clientNum %d", clientNum );
		return;
	}
	
	// TODO: This shouldn't actually happen. Figure out why it does.
	// Seen on clients when another client leaves a match.
	if( msg.GetReadData() == NULL )
	{
		return;
	}
	
	idSerializer ser( msg, false );
	
	usercmd_t fakeCmd;
	usercmd_t* base = &fakeCmd;
	
	usercmd_t lastCmd;
	
	bool										gotNewCmd = false;
	idStaticList< usercmd_t, NUM_USERCMD_RELAY >	newCmdBuffer;
	
	usercmd_t baseCmd = userCmdMgr.NewestUserCmdForPlayer( clientNum );
	int curMilliseconds = baseCmd.clientGameMilliseconds;
	
	const int numCmds = msg.ReadByte();
	
	for( int i = 0; i < numCmds; i++ )
	{
		usercmd_t newCmd;
		newCmd.Serialize( ser, *base );
		
		lastCmd = newCmd;
		base = &lastCmd;
		
		int newMilliseconds = newCmd.clientGameMilliseconds;
		
		if( newMilliseconds > curMilliseconds )
		{
			if( verify( i < NUM_USERCMD_RELAY ) )
			{
				newCmdBuffer.Append( newCmd );
				gotNewCmd = true;
				curMilliseconds = newMilliseconds;
			}
		}
	}
	
	// Push the commands into the buffer.
	for( int i = 0; i < newCmdBuffer.Num(); ++i )
	{
		userCmdMgr.PutUserCmdForPlayer( clientNum, newCmdBuffer[i] );
	}
}
/*
========================
idLobby::HandleUpdateSessionUser
========================
*/
void idLobby::HandleUpdateSessionUser( idBitMsg & msg ) {
	// FIXME: Use a user id here
	int sessionUserIndex = msg.ReadByte();

	lobbyUser_t * user = GetLobbyUser( sessionUserIndex );

	if ( verify( user != NULL ) ) {
		user->ReadClientMutableData( msg );
	}
}
Beispiel #3
0
void rvPlayerStat::UnpackStats( const idBitMsg& msg ) {
	for( int i = 0; i < MAX_WEAPONS; i++ ) {
		weaponShots[ i ] = msg.ReadShort();
	}

	for( int i = 0; i < MAX_WEAPONS; i++ ) {
		weaponHits[ i ] = msg.ReadShort();
	}

	for( int i = 0; i < IGA_NUM_AWARDS; i++ ) {
		inGameAwards[ i ] = msg.ReadByte();
	}

	endGameAwards.SetNum( msg.ReadByte() );
	for( int i = 0; i < endGameAwards.Num(); i++ ) {
		endGameAwards[ i ] = (endGameAward_t)msg.ReadByte();
	}

	deaths = msg.ReadBits( ASYNC_PLAYER_DEATH_BITS );
	kills = msg.ReadBits( ASYNC_PLAYER_KILL_BITS );
}
/*
========================
idLobby::HandleUserConnectFailure
========================
*/
void idLobby::HandleUserConnectFailure( int p, idBitMsg & inMsg, int reliableType ) {
	// Read user to get handle so we can send it back
	inMsg.ReadByte();		// Num users
	lobbyUser_t user;
	user.ReadFromMsg( inMsg );
	
	// Not enough room, send failure ack
	byte buffer[ idPacketProcessor::MAX_PACKET_SIZE ];
	idBitMsg msg( buffer, sizeof( buffer ) );
	user.lobbyUserID.GetLocalUserHandle().WriteToMsg( msg );		// Let peer know which user failed to connect
	
	// Send it
	QueueReliableMessage( p, reliableType, msg.GetReadData(), msg.GetSize() );
}
/*
================
idPhysics_StaticMulti::ReadFromSnapshot
================
*/
void idPhysics_StaticMulti::ReadFromSnapshot( const idBitMsg &msg ) {
	int i, num;
	idCQuat quat, localQuat;

	num = msg.ReadByte();
	assert( num == current.Num() );

	previous = next;

	next.SetNum( num );

	for ( i = 0; i < current.Num(); i++ ) {
		next[i] = ReadStaticInterpolatePStateFromSnapshot( msg );
	}
}
/*
========================
idLobby::ProcessUserDisconnectMsg
========================
*/
void idLobby::ProcessUserDisconnectMsg( idBitMsg & msg ) {

	idList< lobbyUserID_t > removeList;

	// Convert the msg into a list of id's
	const int numUsers			= msg.ReadByte();
	
	for ( int u = 0; u < numUsers; u++ ) {
		lobbyUserID_t lobbyUserID;
		lobbyUserID.ReadFromMsg( msg );
		removeList.Append( lobbyUserID );
	}
	
	RemoveSessionUsersByIDList( removeList );
}
Beispiel #7
0
void idMultiplayerGame::ReceiveAndPlayVoiceData( const idBitMsg &inMsg )
{
	int		clientNum;

	if( !gameLocal.serverInfo.GetBool( "si_voiceChat" ) )
	{
		return;
	}
	
	clientNum = inMsg.ReadByte();
	soundSystem->PlayVoiceData( clientNum, inMsg.GetReadData(), inMsg.GetRemainingData() );
	if( g_voiceChatDebug.GetInteger() & 4 )
	{
		common->Printf( "VC: Playing %d bytes\n", inMsg.GetRemainingData() );
	}
}
Beispiel #8
0
void rvStatManager::ReceiveStat( const idBitMsg& msg ) {
	//asalmon: added because this is used to restore single player stats from saves on Xbox 360
	if(gameLocal.IsMultiplayer())
	{
		assert( gameLocal.isClient );
	}
	
	int client = msg.ReadByte();

	playerStats[ client ].UnpackStats( msg );
	playerStats[ client ].lastUpdateTime = gameLocal.time;

	// display the updated stat
	if(gameLocal.IsMultiplayer())
	{
		statWindow.SelectPlayer( client );
	}
}
Beispiel #9
0
void rvStatManager::ReceiveInGameAward( const idBitMsg& msg ) {
	assert( gameLocal.isClient || gameLocal.isListenServer );
	int numAwards = 0;

	inGameAward_t award = (inGameAward_t)msg.ReadByte();
	int client = msg.ReadByte();

	// display award on hud		
	idPlayer* player = gameLocal.GetLocalPlayer();
	idPlayer* remote = gameLocal.GetClientByNum(client);
	bool justSound = false;
	if ( client != gameLocal.localClientNum ) {
		justSound = true;
	}

	if ( ( gameLocal.time - inGameAwardHudTime ) < 3000 || awardQueue.Num() > 0 ) {
		if ( gameLocal.GetDemoFollowClient() == client || ( player != NULL && remote != NULL && player->GetInstance() == remote->GetInstance() ) ) {
			rvPair<int,bool> awardPair(award, justSound);
			awardQueue.StackAdd(awardPair);
			return;
		}
	}
	
	if( client == gameLocal.localClientNum ) {
		// don't count awards during warmup

		if( !player || (gameLocal.mpGame.GetGameState()->GetMPGameState() != WARMUP && 
			(gameLocal.gameType != GAME_TOURNEY || ((rvTourneyGameState*)gameLocal.mpGame.GetGameState())->GetArena( player->GetArena() ).GetState() != AS_WARMUP )) ) {
			localInGameAwards[ award ]++;
			numAwards = localInGameAwards[ award ];
		} else {
			numAwards = 1;
		}

		if( player && player->mphud ) {
			player->mphud->HandleNamedEvent( "clearIGA" );
			player->mphud->SetStateInt( "ig_awards", idMath::ClampInt( 0, 10, numAwards ) );
			player->mphud->SetStateString( "ig_award", va( "gfx/mp/awards/%s", inGameAwardInfo[ award ].name ) );	
			if( numAwards < 10 ) {
				player->mphud->SetStateString( "ig_award_num", "");
				for( int i = 0; i < idMath::ClampInt( 0, 10, numAwards ); i++ )  {
					player->mphud->SetStateInt( va( "ig_awards_%d", i + 1 ), 1 );
				}
			} else {
				player->mphud->SetStateInt( "ig_award_num", numAwards );
				player->mphud->SetStateInt( "ig_awards", 1  );
				player->mphud->SetStateInt( va( "ig_awards_%d", 1 ), 1 );
			}
			//inGameAwardHudTime = gameLocal.time;
			player->mphud->HandleNamedEvent( "giveIGA" );
			player->mphud->StateChanged( gameLocal.time );

		}

		if ( player ) {
			player->StartSound( va( "snd_award_%s", inGameAwardInfo[ award ].name ), SND_CHANNEL_ANY, 0, false, NULL );
		}
	}
	else if ( player && remote && ( player->GetInstance() == remote->GetInstance() ) && (award == IGA_HOLY_SHIT || award == IGA_CAPTURE || award == IGA_HUMILIATION )) {
			player->StartSound( va( "snd_award_%s", inGameAwardInfo[ award ].name ), SND_CHANNEL_ANY, 0, false, NULL );
	}
	inGameAwardHudTime = gameLocal.time;

	idPlayer* awardee = gameLocal.GetClientByNum( client );
	if ( awardee ) {
		if ( player && player->GetInstance() == awardee->GetInstance() ) {
			iconManager->AddIcon( client, va( "mtr_award_%s", inGameAwardInfo[ award ].name ) );
		}
	}
}
/*
================
idGameLocal::ServerProcessReliableMessage
================
*/
void idGameLocal::ServerProcessReliableMessage( int clientNum, int type, const idBitMsg& msg )
{
	if( clientNum < 0 )
	{
		return;
	}
	switch( type )
	{
		case GAME_RELIABLE_MESSAGE_CHAT:
		case GAME_RELIABLE_MESSAGE_TCHAT:
		{
			char name[128];
			char text[128];
			
			msg.ReadString( name, sizeof( name ) );
			msg.ReadString( text, sizeof( text ) );
			
			mpGame.ProcessChatMessage( clientNum, type == GAME_RELIABLE_MESSAGE_TCHAT, name, text, NULL );
			break;
		}
		case GAME_RELIABLE_MESSAGE_VCHAT:
		{
			int index = msg.ReadLong();
			bool team = msg.ReadBits( 1 ) != 0;
			mpGame.ProcessVoiceChat( clientNum, team, index );
			break;
		}
		case GAME_RELIABLE_MESSAGE_DROPWEAPON:
		{
			mpGame.DropWeapon( clientNum );
			break;
		}
		case GAME_RELIABLE_MESSAGE_EVENT:
		{
			// allocate new event
			entityNetEvent_t* event = eventQueue.Alloc();
			eventQueue.Enqueue( event, idEventQueue::OUTOFORDER_DROP );
			
			event->spawnId = msg.ReadBits( 32 );
			event->event = msg.ReadByte();
			event->time = msg.ReadLong();
			
			event->paramsSize = msg.ReadBits( idMath::BitsForInteger( MAX_EVENT_PARAM_SIZE ) );
			if( event->paramsSize )
			{
				if( event->paramsSize > MAX_EVENT_PARAM_SIZE )
				{
					NetworkEventWarning( event, "invalid param size" );
					return;
				}
				msg.ReadByteAlign();
				msg.ReadData( event->paramsBuf, event->paramsSize );
			}
			break;
		}
		case GAME_RELIABLE_MESSAGE_SPECTATE:
		{
			bool spec = msg.ReadBool();
			idPlayer* player = GetClientByNum( clientNum );
			if( serverInfo.GetBool( "si_spectators" ) )
			{
				// never let spectators go back to game while sudden death is on
				if( mpGame.GetGameState() == idMultiplayerGame::SUDDENDEATH && !spec && player->wantSpectate )
				{
					// Don't allow the change
				}
				else
				{
					if( player->wantSpectate && !spec )
					{
						player->forceRespawn = true;
					}
					player->wantSpectate = spec;
				}
			}
			else
			{
				// If the server turned off si_spectators while a player is spectating, then any spectate message forces the player out of spectate mode
				if( player->wantSpectate )
				{
					player->forceRespawn = true;
				}
				player->wantSpectate = false;
			}
			break;
		}
		case GAME_RELIABLE_MESSAGE_CLIENT_HITSCAN_HIT:
		{
			const int attackerNum = msg.ReadShort();
			const int victimNum = msg.ReadShort();
			idVec3 dir;
			msg.ReadVectorFloat( dir );
			const int damageDefIndex = msg.ReadLong();
			const float damageScale = msg.ReadFloat();
			const int location = msg.ReadLong();
			
			if( gameLocal.entities[victimNum] == NULL )
			{
				break;
			}
			
			if( gameLocal.entities[attackerNum] == NULL )
			{
				break;
			}
			
			idPlayer& victim = static_cast< idPlayer& >( *gameLocal.entities[victimNum] );
			idPlayer& attacker = static_cast< idPlayer& >( *gameLocal.entities[attackerNum] );
			
			if( victim.GetPhysics() == NULL )
			{
				break;
			}
			
			if( attacker.weapon.GetEntity() == NULL )
			{
				break;
			}
			
			if( location == INVALID_JOINT )
			{
				break;
			}
			
			// Line of sight check. As a basic precaution against cheating,
			// the server performs a ray intersection from the client's position
			// to the joint he hit on the target.
			idVec3 muzzleOrigin;
			idMat3 muzzleAxis;
			
			attacker.weapon.GetEntity()->GetProjectileLaunchOriginAndAxis( muzzleOrigin, muzzleAxis );
			
			idVec3 targetLocation = victim.GetRenderEntity()->origin + victim.GetRenderEntity()->joints[location].ToVec3() * victim.GetRenderEntity()->axis;
			
			trace_t tr;
			gameLocal.clip.Translation( tr, muzzleOrigin, targetLocation, NULL, mat3_identity, MASK_SHOT_RENDERMODEL, &attacker );
			
			idEntity* hitEnt = gameLocal.entities[ tr.c.entityNum ];
			if( hitEnt != &victim )
			{
				break;
			}
			const idDeclEntityDef* damageDef = static_cast<const idDeclEntityDef*>( declManager->DeclByIndex( DECL_ENTITYDEF, damageDefIndex, false ) );
			
			if( damageDef != NULL )
			{
				victim.Damage( NULL, gameLocal.entities[attackerNum], dir, damageDef->GetName(), damageScale, location );
			}
			break;
		}
		default:
		{
			Warning( "Unknown reliable message (%d) from client %d", type, clientNum );
			break;
		}
	}
}
/*
========================
idLobby::AddUsersFromMsg
Called on peer and host.
Simply parses a msg, and adds any new users from it to our own user list.
If we are the host, we will forward this to all peers except the peer that we just received it from.
========================
*/
void idLobby::AddUsersFromMsg( idBitMsg & msg, int fromPeer ) {
	int userStart	= GetNumLobbyUsers();
	int numNewUsers = msg.ReadByte();
	
	assert( lobbyBackend != NULL );

	// Add the new users to our own list
	for ( int u = 0; u < numNewUsers; u++ ) {
		lobbyUser_t newUser;
		
		// Read in the new user
		newUser.ReadFromMsg( msg );

		// Initialize their peerIndex and userID if we are the host
		// (we'll send these back to them in the initial connect)
		if ( IsHost() ) {
			if ( fromPeer != -1 ) {		// -1 means this is the host adding his own users, and this stuff is already computed
				// local users will already have this information filled out.
				newUser.address		= peers[ fromPeer ].address; 
				newUser.peerIndex	= fromPeer;
				if ( lobbyType == TYPE_PARTY ) {
					newUser.partyToken = GetPartyTokenAsHost();
				}
			}
		} else {
			assert( fromPeer == host );
			// The host sends us all user addresses, except his local users, so we compute that here
			if ( newUser.peerIndex == -1 ) {
				newUser.address	= peers[ fromPeer ].address;		
			}
		}

		idLib::Printf( "NET: %s joined (%s) [partyToken = %08x].\n", newUser.gamertag, GetLobbyName(), newUser.partyToken );

		lobbyUser_t * appendedUser = NULL;

		// First, try to replace a disconnected user
		for ( int i = 0; i < GetNumLobbyUsers(); i++ ) {
			lobbyUser_t * user = GetLobbyUser( i );

			if ( user->IsDisconnected() ) {
				userStart = i;
				*user = newUser;
				appendedUser = user;
				break;
			}
		}

		// Add them to our list
		if ( appendedUser == NULL ) {
			appendedUser = AllocUser( newUser );
		}

		// Run platform-specific handler after adding
		assert( appendedUser->peerIndex == newUser.peerIndex );		// paranoia
		assert( appendedUser->lobbyUserID == newUser.lobbyUserID );	// paranoia
		RegisterUser( appendedUser );
	}
	
	// Forward list of the new users to all other peers
	if ( IsHost() ) {
		SendNewUsersToPeers( fromPeer, userStart, numNewUsers );
		
		// Set the lobbies skill level
		lobbyBackend->UpdateLobbySkill( GetAverageSessionLevel() );
	}

	idLib::Printf( "---------------- %s --------------------\n", GetLobbyName() );
	for( int userIndex = 0; userIndex < GetNumLobbyUsers(); ++userIndex ) {
		lobbyUser_t * user = GetLobbyUser( userIndex );
		idLib::Printf( "party %08x user %s\n", user->partyToken, user->gamertag );
	}
	idLib::Printf( "---------------- %s --------------------\n", GetLobbyName() );
}