/*
========================
idLobbyBackendDirect::GetConnectInfo
========================
*/
lobbyConnectInfo_t idLobbyBackendDirect::GetConnectInfo() {
	lobbyConnectInfo_t connectInfo;

	// If we aren't the host, this lobby should have been joined through JoinFromConnectInfo
	if ( IsHost() ) {
		// If we are the host, give them our ip address
		const char * ip = Sys_GetLocalIP( 0 );
		Sys_StringToNetAdr( ip, &address, false );
		address.port = net_port.GetInteger();
	}

	connectInfo.netAddr = address;

	return connectInfo;
}
CUT_PBASE_T_USBDI_0474::~CUT_PBASE_T_USBDI_0474()
	{
	OstTraceFunctionEntry1( CUT_PBASE_T_USBDI_0474_CUT_PBASE_T_USBDI_0474_ENTRY_DUP01, this );
	Cancel();
	
	iUsbInterface0.Close();

	delete iClientAction;
	delete iActorFDF;
	if(!IsHost() && iTestDevice)
		{
		iTestDevice->Close();
		}		
	delete iTestDevice;
	OstTraceFunctionExit1( CUT_PBASE_T_USBDI_0474_CUT_PBASE_T_USBDI_0474_EXIT_DUP01, this );
	}
Example #3
0
	//Should keep the script kiddies away.
	//TODO: Replace with a better check
	BOOL CALLBACK AntiTrainer(HWND hwnd, LPARAM lParam)
	{
		char title[80];
		GetWindowText(hwnd, title, sizeof(title));
		if (strcmp(title, "Halo Online Trainer") == 0)
		{
			auto session = Blam::Network::GetActiveSession();
			if (session && session->IsEstablished() && !session->IsHost()) 
			{
				MessageBox(NULL, "Detected Halo Online Trainer!\nOnly hosts are allowed to use a trainer!", "AntiCheat", MB_OK); //Tell the user what they did wrong.
				Modules::CommandMap::Instance().ExecuteCommand("exit"); //exit game
			}
		}

		return TRUE;
	}
/*
========================
idLobby::BecomeHost
========================
*/
void idLobby::BecomeHost()
{

	if( !verify( migrationInfo.state == MIGRATE_PICKING_HOST ) )
	{
		idLib::Printf( "BecomeHost: Must be called from PickNewHost.\n" );
		EndMigration();
		return;
	}
	
	if( IsHost() )
	{
		idLib::Printf( "BecomeHost: Already host of session.\n" );
		EndMigration();
		return;
	}
	
	if( !sessionCB->BecomingHost( *this ) )
	{
		EndMigration();
		return;
	}
	
	idLib::Printf( "BecomeHost: Sending %i invites on %s.\n", migrationInfo.invites.Num(), GetLobbyName() );
	
	migrationInfo.state					= MIGRATE_BECOMING_HOST;
	migrationInfo.migrationStartTime	= Sys_Milliseconds();
	
	if( lobbyBackend == NULL )
	{
		// If we don't have a lobbyBackend, then just create one
		Shutdown();
		StartCreating();
		return;
	}
	
	// Shutdown the current lobby, but keep the lobbyBackend (we'll migrate it)
	Shutdown( true );
	
	// Migrate the lobbyBackend to host
	lobbyBackend->BecomeHost( migrationInfo.invites.Num() );
	
	// Wait for it to complete
	SetState( STATE_CREATE_LOBBY_BACKEND );
}
CUT_PBASE_T_USBDI_0485::~CUT_PBASE_T_USBDI_0485()
	{
	OstTraceFunctionEntry1( CUT_PBASE_T_USBDI_0485_CUT_PBASE_T_USBDI_0485_ENTRY_DUP01, this );
	
	Cancel();
	
	// Close the interface
	iUsbInterface0.Close();
	
	delete iControlEp0;
	delete iActorFDF;
	if(!IsHost() && iTestDevice)
		{
		iTestDevice->Close();
		}		
	delete iTestDevice;
	OstTraceFunctionExit1( CUT_PBASE_T_USBDI_0485_CUT_PBASE_T_USBDI_0485_EXIT_DUP01, this );
	}
Example #6
0
/*
========================
idLobby::KickLobbyUser
========================
*/
void idLobby::KickLobbyUser( lobbyUserID_t lobbyUserID ) {
	if ( !IsHost() ) {
		return;
	}

	const int lobbyUserIndex = GetLobbyUserIndexByID( lobbyUserID );

	lobbyUser_t * user = GetLobbyUser( lobbyUserIndex );

	if ( user != NULL && !IsSessionUserLocal( user ) ) {
		// Send an explicit kick msg, so they know why they were removed
		if ( user->peerIndex >= 0 && user->peerIndex < peers.Num() ) {
			byte buffer[ idPacketProcessor::MAX_MSG_SIZE ];
			idBitMsg msg( buffer, sizeof( buffer ) );
			msg.WriteByte( lobbyUserIndex );
			QueueReliableMessage( user->peerIndex, RELIABLE_KICK_PLAYER, msg.GetReadData(), msg.GetSize() );
		}
	}
}
bool FOnlineSessionNull::NeedsToAdvertise( FNamedOnlineSession& Session )
{
	// In Null, we have to imitate missing online service functionality, so we advertise:
	// a) LAN match with open public connections (same as usually)
	// b) Not started public LAN session (same as usually)
	// d) Joinable presence-enabled session that would be advertised with in an online service
	// (all of that only if we're server)
	return Session.SessionSettings.bShouldAdvertise && IsHost(Session) &&
		(
			(
			  Session.SessionSettings.bIsLANMatch && 			  
			  (Session.SessionState != EOnlineSessionState::InProgress || (Session.SessionSettings.bAllowJoinInProgress && Session.NumOpenPublicConnections > 0))
			) 
			||
			(
				Session.SessionSettings.bAllowJoinViaPresence || Session.SessionSettings.bAllowJoinViaPresenceFriendsOnly
			)
		);		
}
Example #8
0
	void DiscordRPC::UpdatePresence(int networkMode)
	{
		if (Modules::ModuleGame::Instance().VarDiscordEnable->ValueInt == 0)
		{
			Discord_ClearPresence();
			return;
		}

		auto session = Blam::Network::GetActiveSession();
		if (networkMode == 3 && session->IsHost())
		{
			auto thread = CreateThread(NULL, 0, DiscordRetrieveExternalIP_Thread, NULL, 0, NULL);
		}
		else
		{
			joinString = "";
		}
		UpdatePresence();
	}
Example #9
0
/*
========================
idLobby::RequestSessionUserDisconnect
Sends a request to the host to remove a session user from the session.
If we are the host, we will do it immediately.
========================
*/
void idLobby::RequestSessionUserDisconnect( int sessionUserIndex ) {

	if ( !IsRunningAsHostOrPeer() ) {
		// If we are not in an actual running session, just remove it.
		// This is so we accurately reflect the local user list through the session users in the menus, etc.
		// FIXME:
		// This is a total hack, and we should really look at better separation of local users/session users
		// and not rely on session users while in the menus. 
		FreeUser( GetLobbyUser( sessionUserIndex ) );
		return;
	}
	
	lobbyUser_t * lobbyUser = GetLobbyUser( sessionUserIndex );

	if ( !verify( lobbyUser != NULL ) ) {
		return;
	}
	
	if ( lobbyUser->disconnecting == true ) {
		return;		// Already disconnecting
	}

	byte buffer[ idPacketProcessor::MAX_PACKET_SIZE ];
	idBitMsg msg( buffer, sizeof( buffer ) );
	
	msg.WriteByte( 1 );	// 1 user
	lobbyUser->lobbyUserID.WriteToMsg( msg );
	
	if ( IsHost() ) {
		idBitMsg readMsg;
		readMsg.InitRead( msg.GetReadData(), msg.GetSize() );

		// As the host, just disconnect immediately (we'll still send the notification to all peers though)
		ProcessUserDisconnectMsg( readMsg );
	} else {
		// Send the message
		QueueReliableMessage( host, RELIABLE_USER_DISCONNECT_REQUEST, msg.GetReadData(), msg.GetSize() );
		
		// Mark user as disconnecting to make sure we don't keep sending the request
		lobbyUser->disconnecting = true;
	}
}
CUT_PBASE_T_USBDI_0481::~CUT_PBASE_T_USBDI_0481()
	{
	OstTraceFunctionEntry1( CUT_PBASE_T_USBDI_0481_CUT_PBASE_T_USBDI_0481_ENTRY_DUP01, this );
	
	Cancel();
	
	// Close interfaces	
	iUsbInterface0.Close();
	iUsbInterface1.Close();
	
	// Free resources
	delete iControlEp0;
	delete iActorFDF;
	if(!IsHost() && iTestDevice)
		{
		iTestDevice->Close();
		}		
	delete iTestDevice;
	OstTraceFunctionExit1( CUT_PBASE_T_USBDI_0481_CUT_PBASE_T_USBDI_0481_EXIT_DUP01, this );
	}
Example #11
0
/*
========================
idLobby::RequestLocalUserJoin
Sends a request to the host to join a local user to a session.
If we are the host, we will do it immediately.
========================
*/
void idLobby::RequestLocalUserJoin( idLocalUser * localUser ) {
	assert( IsRunningAsHostOrPeer() );

	// Construct a msg that contains the user connect request
	lobbyUser_t lobbyUser = CreateLobbyUserFromLocalUser( localUser );
	
	byte buffer[ idPacketProcessor::MAX_PACKET_SIZE ];
	idBitMsg msg( buffer, sizeof( buffer ) );
	
	msg.WriteByte( 1 );					// 1 user
	lobbyUser.WriteToMsg( msg );		// Write user

	if ( IsHost() ) {
		AddUsersFromMsg( msg, -1 );
		localUser->SetJoiningLobby( lobbyType, false );
	} else {
		// Send request to host to add user
		QueueReliableMessage( host, RELIABLE_USER_CONNECT_REQUEST, msg.GetReadData(), msg.GetSize() );
	}
}
Example #12
0
//-----------------------------------------------------------------------------
// Purpose: Migrate the session to a new host
//-----------------------------------------------------------------------------
bool CSession::MigrateHost()
{
	if ( IsHost() )
	{
		// Migrate call will fill this in for us
		Q_memcpy( &m_NewSessionInfo, &m_SessionInfo, sizeof( m_NewSessionInfo ) );
	}

	m_hMigrateHandle = g_pXboxSystem->CreateAsyncHandle();

	int ret = g_pXboxSystem->SessionMigrate( m_hSession, m_nOwnerId, &m_NewSessionInfo, true, &m_hMigrateHandle );
	if ( ret != ERROR_IO_PENDING )
	{
		return false;
	}

	SwitchToState( SESSION_STATE_MIGRATING );

	return true;
}
Example #13
0
/*
========================
idLobby::RemoveUsersWithDisconnectedPeers
Go through each user, and remove the ones that have a peer marked as disconnected
NOTE - This should only be called from the host.  The host will call RemoveSessionUsersByIDList, 
which will forward the action to the connected peers.
========================
*/
void idLobby::RemoveUsersWithDisconnectedPeers() {
	if ( !verify( IsHost() ) ) {	
		// We're not allowed to do this unless we are the host of this session type
		// If we are the host, RemoveSessionUsersByIDList will forward the call to peers.
		return;
	}

	idList< lobbyUserID_t > removeList;
	for ( int u = 0; u < GetNumLobbyUsers(); u++ ) {
		lobbyUser_t * user = GetLobbyUser( u );
		if ( !verify( user != NULL ) ) {
			continue;
		}
		if ( IsSessionUserIndexLocal( u ) || user->IsDisconnected() ) {
			continue;
		}

		if ( user->peerIndex == -1 ) {
			// Wanting to know if this actually happens.  
			// If this is a user on the hosts machine, IsSessionUserIndexLocal should catch it above.
			assert( false );		
			// The user is on the host.
			// The host's peer is disconnected via other mechanisms that I don't have a firm
			// grasp on yet.
			continue;
		}

		if ( user->peerIndex >= peers.Num() ) {
			// TTimo - I am hitting this in ~12 client games for some reason?
			// only throwing an assertion in debug, with no crashing, so adding a warning verbose
			idLib::Warning( "idLobby::RemoveUsersWithDisconnectedPeers: user %d %s is out of range in the peers list (%d elements)", u, user->gamertag, peers.Num() );
			continue;
		}
		peer_t & peer = peers[ user->peerIndex ];
		if ( peer.GetConnectionState() != CONNECTION_ESTABLISHED ) {
			removeList.Append( user->lobbyUserID );
		}
	}

	RemoveSessionUsersByIDList( removeList );
}
Example #14
0
Vector<ValueType> Vector<ValueType>::operator+(
                                const Vector<ValueType>& otherVector)
{
    DEBUGLOG( this, "Vector::operator+", "Vec =" << &otherVector, 1);
    assert(GetSize() == otherVector.GetSize());
    assert(( IsHost() && otherVector.IsHost() )|| 
            (IsDevice() && otherVector.IsDevice()) );

    Vector<ValueType> result(GetSize());

    if (pImpl == pImplHost)
        result.pImpl->Add(*(otherVector.pImpl), *pImpl);
    else if (pImpl == pImplDevice)
    {
        result.MoveToDevice();
        result.pImpl->Add(*(otherVector.pImpl), *pImpl);
    }

    DEBUGEND();
    return result;
        
}
void CNetManager::SendLocalCharacterUpdates()
{
	if(Connected())
	{
		std::vector<CCharacterObject*>::iterator playerIter;
		for(playerIter = localPlayerCharactersVectorRef->begin(); playerIter != localPlayerCharactersVectorRef->end(); playerIter++)
		{
			if((*playerIter)->IsMovementUpdate())
			{
				SendCharacterMovement(*(*playerIter));
			}
		}
		if(IsHost())
		{
			std::vector<CEnemyObject*>::iterator enemyIter;
			for(enemyIter = localEnemiesVectorRef->begin(); enemyIter != localEnemiesVectorRef->end(); enemyIter++)
			{
				SendCharacterMovement(*(*enemyIter));
			}
		}
	}
}
Example #16
0
QueryError OnSessionInfo(const rapidjson::Value &p_Args, std::string *p_Result)
{
    rapidjson::StringBuffer buffer;
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

    writer.StartObject();
    auto session = Blam::Network::GetActiveSession();
    if (!session || !session->IsEstablished())
    {
        writer.Key("established");
        writer.Bool(false);

        writer.Key("hasTeams");
        writer.Bool(false);

        writer.Key("isHost");
        writer.Bool(false);
    }
    else
    {
        writer.Key("established");
        writer.Bool(true);

        writer.Key("hasTeams");
        writer.Bool(session->HasTeams());

        writer.Key("isHost");
        writer.Bool(session->IsHost());
    }
    writer.Key("mapName");
    writer.String((char*)Pointer(0x22AB018)(0x1A4));

    writer.EndObject();

    *p_Result = buffer.GetString();
    return QueryError_Ok;
}
Example #17
0
/*
========================
idLobby::HandleHeadsetStateChange
========================
*/
void idLobby::HandleHeadsetStateChange( int fromPeer, idBitMsg & msg ) {
	int userCount = msg.ReadLong();
	
	for ( int i = 0; i < userCount; ++i ) {
		lobbyUserID_t lobbyUserID;
		lobbyUserID.ReadFromMsg( msg );
		bool state = msg.ReadBool();
		
		int talkerIndex = sessionCB->GetVoiceChat()->FindTalkerByUserId( lobbyUserID, lobbyType );
		sessionCB->GetVoiceChat()->SetHeadsetState( talkerIndex, state );

		idLib::Printf( "User %d headset status: %d\n", talkerIndex, state );

		// If we are the host, let the other clients know about the headset state of this peer
		if ( IsHost() ) {

			// We should not be receiving a message with a user count > 1 if we are the host
			assert( userCount == 1 );

			byte buffer[ idPacketProcessor::MAX_MSG_SIZE ];
			idBitMsg outMsg( buffer, sizeof( buffer ) );
			outMsg.WriteLong( 1 );
			lobbyUserID.WriteToMsg( outMsg );
			outMsg.WriteBool( state );

			for ( int j = 0; j < peers.Num(); ++j ) {
				// Don't send this to the player that we just received the message from
				if ( !peers[ j ].IsConnected() || j == fromPeer ) {
					continue;
				}

				QueueReliableMessage( j, RELIABLE_HEADSET_STATE, outMsg.GetReadData(), outMsg.GetSize() );
			}
		}
	}
}
Example #18
0
/*
========================
idLobby::UpdateLocalSessionUsers
======================== 
*/
void idLobby::UpdateLocalSessionUsers() {
	for ( int i = 0; i < GetNumLobbyUsers(); i++ ) {
		idLocalUser * localUser = GetLocalUserFromLobbyUserIndex( i );
		lobbyUser_t * lobbyUser = GetLobbyUser( i );

		if ( localUser == NULL || lobbyUser == NULL ) {
			continue;
		}
		if ( !lobbyUser->UpdateClientMutableData( localUser ) ) {
			continue;
		}

		byte buffer[ idPacketProcessor::MAX_PACKET_SIZE - 2 ];
		idBitMsg msg( buffer, sizeof( buffer ) );

		CreateUserUpdateMessage( i, msg );

		if ( IsHost() ) {
			UpdateSessionUserOnPeers( msg );
		} else if ( IsPeer() ) {
			QueueReliableMessage( host, RELIABLE_SESSION_USER_MODIFIED, msg.GetReadData(), msg.GetSize() );
		}
	}
}
/*
========================
idLobby::UpdateHostMigration
========================
*/
void idLobby::UpdateHostMigration()
{

	int time = Sys_Milliseconds();
	
	// If we are picking a new host, then update that
	if( migrationInfo.state == MIGRATE_PICKING_HOST )
	{
		const int MIGRATION_PICKING_HOST_TIMEOUT_IN_SECONDS = 20;		// FIXME: set back to 5 // Give other hosts 5 seconds
		
		if( time - migrationInfo.migrationStartTime > session->GetTitleStorageInt( "MIGRATION_PICKING_HOST_TIMEOUT_IN_SECONDS", MIGRATION_PICKING_HOST_TIMEOUT_IN_SECONDS ) * 1000 )
		{
			// Just become the host if we haven't heard from a host in awhile
			BecomeHost();
		}
		else
		{
			return;
		}
	}
	
	// See if we are a new migrated host that needs to invite the original members back
	if( migrationInfo.state != MIGRATE_BECOMING_HOST )
	{
		return;
	}
	
	if( lobbyBackend == NULL || lobbyBackend->GetState() != idLobbyBackend::STATE_READY )
	{
		return;
	}
	
	if( state != STATE_IDLE )
	{
		return;
	}
	
	if( !IsHost() )
	{
		return;
	}
	
	const int MIGRATION_TIMEOUT_IN_SECONDS		= 30; // FIXME: setting to 30 for dev purposes. 10 seems more reasonable. Need to make unloading game / loading lobby async
	const int MIGRATION_INVITE_TIME_IN_SECONDS	= 2;
	
	if( migrationInfo.invites.Num() == 0 || time - migrationInfo.migrationStartTime > session->GetTitleStorageInt( "MIGRATION_TIMEOUT_IN_SECONDS", MIGRATION_TIMEOUT_IN_SECONDS ) * 1000 )
	{
		// Either everyone acked, or we timed out, just keep who we have, and stop sending invites
		EndMigration();
		return;
	}
	
	// Send invites to anyone who hasn't responded
	for( int i = 0; i < migrationInfo.invites.Num(); i++ )
	{
		if( time - migrationInfo.invites[i].lastInviteTime < session->GetTitleStorageInt( "MIGRATION_INVITE_TIME_IN_SECONDS", MIGRATION_INVITE_TIME_IN_SECONDS ) * 1000 )
		{
			continue;		// Not enough time passed
		}
		
		// Mark the time
		migrationInfo.invites[i].lastInviteTime = time;
		
		byte buffer[ idPacketProcessor::MAX_PACKET_SIZE - 2 ];
		idBitMsg outmsg( buffer, sizeof( buffer ) );
		
		// Have lobbyBackend fill out msg with connection info
		lobbyConnectInfo_t connectInfo = lobbyBackend->GetConnectInfo();
		connectInfo.WriteToMsg( outmsg );
		
		// Let them know whether or not this was from in game
		outmsg.WriteBool( migrationInfo.persistUntilGameEndsData.wasMigratedGame );
		
		NET_VERBOSE_PRINT( "NET: Sending migration invite to %s\n", migrationInfo.invites[i].address.ToString() );
		
		// Send the migration invite
		SendConnectionLess( migrationInfo.invites[i].address, OOB_MIGRATE_INVITE, outmsg.GetReadData(), outmsg.GetSize() );
	}
}
/*
========================
idLobby::PickNewHostInternal
========================
*/
void idLobby::PickNewHostInternal( bool forceMe, bool inviteOldHost )
{

	if( migrationInfo.state == MIGRATE_PICKING_HOST )
	{
		return;		// Already picking new host
	}
	
	idLib::Printf( "PickNewHost: Started picking new host %s.\n", GetLobbyName() );
	
	if( IsHost() )
	{
		idLib::Printf( "PickNewHost: Already host of session %s\n", GetLobbyName() );
		return;
	}
	
	// Find the user with the lowest ping
	int bestUserIndex			= -1;
	int bestPingMs				= 0;
	lobbyUserID_t bestUserId;
	
	for( int i = 0; i < GetNumLobbyUsers(); i++ )
	{
		lobbyUser_t* user = GetLobbyUser( i );
		
		if( !verify( user != NULL ) )
		{
			continue;
		}
		
		if( user->IsDisconnected() )
		{
			continue;
		}
		
		if( user->peerIndex == -1 )
		{
			continue;		// Don't try and pick old host
		}
		
		if( bestUserIndex == -1 || IsBetterHost( user->pingMs, user->lobbyUserID, bestPingMs, bestUserId ) )
		{
			bestUserIndex	= i;
			bestPingMs		= user->pingMs;
			bestUserId		= user->lobbyUserID;
		}
		
		if( user->peerIndex == net_migration_forcePeerAsHost.GetInteger() )
		{
			bestUserIndex	= i;
			bestPingMs		= user->pingMs;
			bestUserId		= user->lobbyUserID;
			break;
		}
	}
	
	// Remember when we first started picking a new host
	migrationInfo.state						= MIGRATE_PICKING_HOST;
	migrationInfo.migrationStartTime		= Sys_Milliseconds();
	
	migrationInfo.persistUntilGameEndsData.wasMigratedGame = sessionCB->GetState() == idSession::INGAME;
	
	if( bestUserIndex == -1 )  	// This can happen if we call PickNewHost on an lobby that was Shutdown
	{
		NET_VERBOSE_PRINT( "MIGRATION: PickNewHost was called on an lobby that was Shutdown\n" );
		BecomeHost();
		return;
	}
	
	NET_VERBOSE_PRINT( "MIGRATION: Chose user index %d (%s) for new host\n", bestUserIndex, GetLobbyUser( bestUserIndex )->gamertag );
	
	bool bestWasLocal = IsSessionUserIndexLocal( bestUserIndex );		// Check before shutting down the lobby
	migrateMsgFlags = parms.matchFlags;						// Save off match parms
	
	// Build invite list
	BuildMigrationInviteList( inviteOldHost );
	
	// If the best user is on this machine, then we become the host now, otherwise, wait for a new host to contact us
	if( forceMe || bestWasLocal )
	{
		BecomeHost();
	}
}
Example #21
0
	bool CommandMap::ExecuteCommandWithStatus(std::string command, bool isUserInput, std::string *output)
	{
		*output = "";

		int numArgs = 0;
		auto args = CommandLineToArgvA((PCHAR)command.c_str(), &numArgs);

		if (numArgs <= 0)
		{
			*output = "Invalid input";
			return false;
		}

		auto cmd = FindCommand(args[0]);
		if (!cmd || (isUserInput && cmd->Flags & eCommandFlagsInternal))
		{
			*output = "Command/Variable not found";
			return false;
		}

		if ((cmd->Flags & eCommandFlagsRunOnMainMenu) && !ElDorito::Instance().GameHasMenuShown)
		{
			queuedCommands.push_back(command);
			*output = "Command queued until mainmenu shows";
			return true;
		}

		// Host-only commands
		if (cmd->Flags & eCommandFlagsCheat || cmd->Flags & eCommandFlagsHostOnly)
		{
			auto session = Blam::Network::GetActiveSession();
			if (session && session->IsEstablished() && !session->IsHost())
			{
				*output = "Only a player hosting a game can use this command";
				return false;
			}
		}

		std::vector<std::string> argsVect;
		if (numArgs > 1)
			for (int i = 1; i < numArgs; i++)
				argsVect.push_back(args[i]);

		if (cmd->Type == eCommandTypeCommand && cmd->Flags == eCommandFlagsArgsNoParse)
		{
			argsVect.clear();
			if (numArgs >= 2)
				argsVect.push_back(command.substr(std::strlen(args[0]) + 1)); //push unparsed arguments after the command
			return cmd->UpdateEvent(argsVect, *output);
		}

		if (cmd->Type == eCommandTypeCommand)
			return cmd->UpdateEvent(argsVect, *output); // if it's a command call it and return

		if (numArgs <= 1)
		{
			*output = cmd->ValueString;
			return true;
		}

		std::string previousValue;
		auto updateRet = SetVariable(cmd, argsVect[0], previousValue);
		switch (updateRet)
		{
		case eVariableSetReturnValueError:
			*output = "Command/variable not found";
			return false;
		case eVariableSetReturnValueInvalidArgument:
			*output = "Invalid value";
			return false;
		case eVariableSetReturnValueOutOfRange:
			if (cmd->Type == eCommandTypeVariableInt)
				*output = "Value " + argsVect[0] + " out of range [" + std::to_string(cmd->ValueIntMin) + ".." + std::to_string(cmd->ValueIntMax) + "]";
			else if (cmd->Type == eCommandTypeVariableInt64)
				*output = "Value " + argsVect[0] + " out of range [" + std::to_string(cmd->ValueInt64Min) + ".." + std::to_string(cmd->ValueInt64Max) + "]";
			else if (cmd->Type == eCommandTypeVariableFloat)
				*output = "Value " + argsVect[0] + " out of range [" + std::to_string(cmd->ValueFloatMin) + ".." + std::to_string(cmd->ValueFloatMax) + "]";
			else
				*output = "Value " + argsVect[0] + " out of range [this shouldn't be happening!]";
			return false;
		}

		if (!cmd->UpdateEvent)
		{
			*output = previousValue + " -> " + cmd->ValueString; // no update event, so we'll just return with what we set the value to
			return true;
		}

		auto ret = cmd->UpdateEvent(argsVect, *output);

		if (!ret) // error, revert the variable
			this->SetVariable(cmd, previousValue, std::string());

		if (output->length() <= 0)
			*output = previousValue + " -> " + cmd->ValueString;

		return ret;
	}
Example #22
0
/*
========================
idLobby::CheckPeerThrottle
========================
*/
void idLobby::CheckPeerThrottle( int p )
{
	assert( lobbyType == GetActingGameStateLobbyType() );
	
	if( !verify( p >= 0 && p < peers.Num() ) )
	{
		return;
	}
	
	peer_t& peer = peers[p];
	
	if( !peer.IsConnected() )
	{
		return;
	}
	
	if( !IsHost() )
	{
		return;
	}
	
	if( session->GetTitleStorageInt( "net_peer_throttle_mode", net_peer_throttle_mode.GetInteger() ) == 0 )
	{
		return;
	}
	
	if( peer.receivedBps < 0.0f )
	{
		return;
	}
	
	int time = Sys_Milliseconds();
	
	if( !AllPeersHaveBaseState() )
	{
		return;
	}
	
	if( verify( peer.snapProc != NULL ) )
	{
		const int peer_throttle_minSnapSeq = session->GetTitleStorageInt( "net_peer_throttle_minSnapSeq", net_peer_throttle_minSnapSeq.GetInteger() );
		if( peer.snapProc->GetFullSnapBaseSequence() <= idSnapshotProcessor::INITIAL_SNAP_SEQUENCE + peer_throttle_minSnapSeq )
		{
			return;
		}
	}
	
	// This is bps throttling which compares the sent bytes per second to the reported received bps
	float peer_throttle_bps_host_threshold = session->GetTitleStorageFloat( "net_peer_throttle_bps_host_threshold", net_peer_throttle_bps_host_threshold.GetFloat() );
	
	if( peer_throttle_bps_host_threshold > 0.0f )
	{
		int deltaT = idMath::ClampInt( 0, 100, time - peer.receivedThrottleTime );
		if( deltaT > 0 && peer.receivedThrottleTime > 0 && peer.receivedBpsIndex > 0 )
		{
		
			bool throttled = false;
			float sentBps = peer.sentBpsHistory[ peer.receivedBpsIndex % MAX_BPS_HISTORY ];
			
			// Min outgoing rate from server (don't throttle if we are sending < 1k)
			if( sentBps > peer_throttle_bps_host_threshold )
			{
				float pct = peer.receivedBps / idMath::ClampFloat( 0.01f, static_cast<float>( BANDWIDTH_REPORTING_MAX ), sentBps ); // note the receivedBps is implicitly clamped on client end to 10k/sec
				
				/*
				static int lastSeq = 0;
				if ( peer.receivedBpsIndex != lastSeq ) {
					NET_VERBOSE_PRINT( "%ssentBpsHistory[%d] = %.2f   received: %.2f PCT: %.2f \n", ( pct > 1.0f ? "^1" : "" ), peer.receivedBpsIndex, sentBps, peer.receivedBps, pct );
				}
				lastSeq = peer.receivedBpsIndex;
				*/
				
				// Increase throttle time if peer is < % of what we are sending him
				if( pct < session->GetTitleStorageFloat( "net_peer_throttle_bps_peer_threshold_pct", net_peer_throttle_bps_peer_threshold_pct.GetFloat() ) )
				{
					peer.receivedThrottle += ( float )deltaT;
					throttled = true;
					NET_VERBOSE_PRINT( "NET: throttled... %.2f ....pct %.2f  receivedBps %.2f outgoingBps %.2f, peer %i, seq %i\n", peer.receivedThrottle, pct, peer.receivedBps, sentBps, p, peer.snapProc->GetFullSnapBaseSequence() );
				}
			}
			
			if( !throttled )
			{
				float decayRate = session->GetTitleStorageFloat( "net_peer_throttle_bps_decay", net_peer_throttle_bps_decay.GetFloat() );
				
				peer.receivedThrottle = Max<float>( 0.0f, peer.receivedThrottle - ( ( ( float )deltaT ) * decayRate ) );
				//NET_VERBOSE_PRINT("NET: !throttled... %.2f ....receivedBps %.2f outgoingBps %.2f\n", peer.receivedThrottle, peer.receivedBps, sentBps );
			}
			
			float duration = session->GetTitleStorageFloat( "net_peer_throttle_bps_duration", net_peer_throttle_bps_duration.GetFloat() );
			
			if( peer.receivedThrottle > duration )
			{
				peer.maxSnapBps = peer.receivedBps * session->GetTitleStorageFloat( "net_snap_bw_test_throttle_max_scale", net_snap_bw_test_throttle_max_scale.GetFloat() );
				
				int maxRate = common->GetSnapRate() * session->GetTitleStorageInt( "net_peer_throttle_maxSnapRate", net_peer_throttle_maxSnapRate.GetInteger() );
				
				if( peer.throttledSnapRate == 0 )
				{
					peer.throttledSnapRate = common->GetSnapRate() * 2;
				}
				else if( peer.throttledSnapRate < maxRate )
				{
					peer.throttledSnapRate = idMath::ClampInt( common->GetSnapRate(), maxRate, peer.throttledSnapRate + common->GetSnapRate() );
				}
				
				peer.receivedThrottle = 0.0f;	// Start over, so we don't immediately throttle again
			}
		}
		peer.receivedThrottleTime = time;
	}
}
Example #23
0
/*
========================
idLobby::SendCompletedPendingSnap
========================
*/
void idLobby::SendCompletedPendingSnap( int p )
{

	assert( lobbyType == GetActingGameStateLobbyType() );
	
	int time = Sys_Milliseconds();
	
	peer_t& peer = peers[p];
	
	if( !peer.IsConnected() )
	{
		return;
	}
	
	if( peer.snapProc == NULL || !peer.snapProc->PendingSnapReadyToSend() )
	{
		return;
	}
	
	// If we have a pending snap ready to send, we better have a pending snap
	assert( peer.snapProc->HasPendingSnap() );
	
	// Get the snap data blob now, even if we don't send it.
	// This is somewhat wasteful, but we have to do this to keep the snap job pipe ready to keep doing work
	// If we don't do this, this peer will cause other peers to be starved of snapshots, when they may very well be ready to send a snap
	byte buffer[ MAX_SNAP_SIZE ];
	int maxLength = sizeof( buffer ) - peer.packetProc->GetReliableDataSize() - 128;
	
	int size = peer.snapProc->GetPendingSnapDelta( buffer, maxLength );
	
	if( !CanSendMoreData( p ) )
	{
		return;
	}
	
	// Can't send anymore snapshots until all fragments are sent
	if( peer.packetProc->HasMoreFragments() )
	{
		return;
	}
	
	// If the peer doesn't have the latest resource list, send it to him before sending any new snapshots
	if( SendResources( p ) )
	{
		return;
	}
	
	int timeFromJobSub = time - peer.lastSnapJobTime;
	int timeFromLastSend = time - peer.lastSnapTime;
	
	if( timeFromLastSend > 0 )
	{
		peer.snapHz = 1000.0f / ( float )timeFromLastSend;
	}
	else
	{
		peer.snapHz = 0.0f;
	}
	
	if( net_snapshot_send_warntime.GetInteger() > 0 && peer.lastSnapTime != 0 && net_snapshot_send_warntime.GetInteger() < timeFromLastSend )
	{
		idLib::Printf( "NET: Took %d ms to send peer %d snapshot\n", timeFromLastSend, p );
	}
	
	if( peer.throttleSnapsForXSeconds != 0 )
	{
		if( time < peer.throttleSnapsForXSeconds )
		{
			return;
		}
		
		// If we were trying to recover ping, see if we succeeded
		if( peer.recoverPing != 0 )
		{
			if( peer.lastPingRtt >= peer.recoverPing )
			{
				peer.failedPingRecoveries++;
			}
			else
			{
				const int peer_throttle_minSnapSeq = session->GetTitleStorageInt( "net_peer_throttle_minSnapSeq", net_peer_throttle_minSnapSeq.GetInteger() );
				if( peer.snapProc->GetFullSnapBaseSequence() > idSnapshotProcessor::INITIAL_SNAP_SEQUENCE + peer_throttle_minSnapSeq )
				{
					// If throttling recovered the ping
					int maxRate = common->GetSnapRate() * session->GetTitleStorageInt( "net_peer_throttle_maxSnapRate", net_peer_throttle_maxSnapRate.GetInteger() );
					peer.throttledSnapRate = idMath::ClampInt( common->GetSnapRate(), maxRate, peer.throttledSnapRate + common->GetSnapRate() );
				}
			}
		}
		
		peer.throttleSnapsForXSeconds = 0;
	}
	
	peer.lastSnapTime = time;
	
	if( size != 0 )
	{
		if( size > 0 )
		{
			NET_VERBOSESNAPSHOT_PRINT_LEVEL( 3, va( "NET: (peer %d) Sending snapshot %d delta'd against %d. Since JobSub: %d Since LastSend: %d. Size: %d\n", p, peer.snapProc->GetSnapSequence(), peer.snapProc->GetBaseSequence(), timeFromJobSub, timeFromLastSend, size ) );
			ProcessOutgoingMsg( p, buffer, size, false, 0 );
		}
		else if( size < 0 )  	// Size < 0 indicates the delta buffer filled up
		{
			// There used to be code here that would disconnect peers if they were in game and filled up the buffer
			// This was causing issues in the playtests we were running (Doom 4 MP) and after some conversation
			// determined that it was not needed since a timeout mechanism has been added since
			ProcessOutgoingMsg( p, buffer, -size, false, 0 );
			if( peer.snapProc != NULL )
			{
				NET_VERBOSESNAPSHOT_PRINT( "NET: (peerNum: %d - name: %s) Resending last snapshot delta %d because his delta list filled up. Since JobSub: %d Since LastSend: %d Delta Size: %d\n", p, GetPeerName( p ), peer.snapProc->GetSnapSequence(), timeFromJobSub, timeFromLastSend, size );
			}
		}
	}
	
	// We calculate what our outgoing rate was for each sequence, so we can have a relative comparison
	// for when the client reports what his downstream was in the same timeframe
	if( IsHost() && peer.snapProc != NULL && peer.snapProc->GetSnapSequence() > 0 )
	{
		//NET_VERBOSE_PRINT("^8  %i Rate: %.2f   SnapSeq: %d GetBaseSequence: %d\n", lastAppendedSequence, peer.packetProc->GetOutgoingRateBytes(), peer.snapProc->GetSnapSequence(), peer.snapProc->GetBaseSequence() );
		peer.sentBpsHistory[ peer.snapProc->GetSnapSequence() % MAX_BPS_HISTORY ] = peer.packetProc->GetOutgoingRateBytes();
	}
}
Example #24
0
/*
========================
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() );
}