Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Handles host migration for a session (not for the game server)
//
//=============================================================================//
#include "matchmaking.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Start a Matchmaking session as the host
//-----------------------------------------------------------------------------
CClientInfo *CMatchmaking::SelectNewHost() { // For now, just grab the first guy in the list
CClientInfo *pClient = &m_Local; for ( int i = 0; i < m_Remote.Count(); ++i ) { if ( m_Remote[i]->m_id > pClient->m_id ) { pClient = m_Remote[i]; } } return pClient; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMatchmaking::StartHostMigration() { SwitchToState( MMSTATE_HOSTMIGRATE_STARTINGMIGRATION );
m_pNewHost = SelectNewHost(); if ( m_pNewHost == &m_Local ) { // We're the new host, so start hosting
Msg( "Starting new host" ); BeginHosting(); } else { Msg( "Waiting for a new host" ); SwitchToNewHost(); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMatchmaking::BeginHosting() { m_Session.SetIsHost( true ); m_Host = m_Local;
// Move into private slots
if ( !m_Local.m_bInvited ) { RemovePlayersFromSession( &m_Local ); m_Local.m_bInvited = true; AddPlayersToSession( &m_Local ); }
if ( !m_Session.MigrateHost() ) { Warning( "Session migrate failed!\n" );
SessionNotification( SESSION_NOTIFY_FAIL_MIGRATE ); return; }
SwitchToState( MMSTATE_HOSTMIGRATE_MIGRATING ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMatchmaking::TellClientsToMigrate() { Msg( "Sending migrate request\n" );
XSESSION_INFO info; m_Session.GetNewSessionInfo( &info );
MM_Migrate msg; msg.m_MsgType = MM_Migrate::MESSAGE_HOSTING; msg.m_Id = m_Local.m_id; msg.m_sessionId = info.sessionID; msg.m_xnaddr = info.hostAddress; msg.m_key = info.keyExchangeKey;
for ( int i = 0; i < m_Remote.Count(); ++i ) { if ( m_Remote[i]->m_bMigrated ) { continue; }
SendMessage( &msg, &m_Remote[i]->m_adr ); }
m_fSendTimer = GetTime(); ++m_nSendCount; }
//-----------------------------------------------------------------------------
// Purpose: Handle a migration message from our new host
//-----------------------------------------------------------------------------
bool CMatchmaking::ProcessMigrate( MM_Migrate *pMsg ) { MM_Migrate reply; int type = pMsg->m_MsgType;
if ( m_CurrentState == MMSTATE_HOSTMIGRATE_WAITINGFORHOST ) { if ( type == MM_Migrate::MESSAGE_HOSTING ) { // Make sure this is the host we were expecting
if ( !Q_memcmp( &pMsg->m_xnaddr, &m_Host.m_xnaddr, sizeof( m_Host.m_xnaddr ) ) ) { // Reply to the host
reply.m_MsgType = MM_Migrate::MESSAGE_MIGRATED; reply.m_xnaddr = m_Local.m_xnaddr; SendMessage( &reply, &m_Host.m_adr );
XSESSION_INFO info; info.sessionID = pMsg->m_sessionId; info.hostAddress = pMsg->m_xnaddr; info.keyExchangeKey = pMsg->m_key;
m_Session.SetNewSessionInfo( &info ); m_Session.SetOwnerId( XUSER_INDEX_NONE );
if ( !m_Session.MigrateHost() ) { Warning( "Session migrate failed!\n" );
SessionNotification( SESSION_NOTIFY_FAIL_MIGRATE ); return true; }
SwitchToState( MMSTATE_HOSTMIGRATE_MIGRATING ); } else { // Someone else is trying to host
reply.m_MsgType = MM_Migrate::MESSAGE_STANDBY; SendMessage( &reply, &m_Host.m_adr ); } } } else if ( m_CurrentState == MMSTATE_HOSTMIGRATE_WAITINGFORCLIENTS ) { if ( type == MM_Migrate::MESSAGE_MIGRATED ) { // Flag the client as having migrated
bool bClientsOutstanding = false;
for ( int i = 0; i < m_Remote.Count(); ++i ) { if ( m_Remote[i]->m_id == pMsg->m_Id ) { m_Remote[i]->m_bMigrated = true; }
bClientsOutstanding = bClientsOutstanding && m_Remote[i]->m_bMigrated; }
if ( !bClientsOutstanding ) { // Everyone's migrated!
EndMigration(); } }
if ( type == MM_Migrate::MESSAGE_STANDBY ) { // Someone requested a standby
--m_nSendCount; } }
return true; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMatchmaking::SwitchToNewHost() { // Set a timer to wait for the host to contact us
m_fWaitTimer = GetTime();
// Get rid of the current host net channel
MarkChannelForRemoval( &m_Host.m_adr );
AddRemoteChannel( &m_pNewHost->m_adr );
SwitchToState( MMSTATE_HOSTMIGRATE_WAITINGFORHOST ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMatchmaking::EndMigration() { Msg( "Migration complete\n" );
if ( m_Session.IsHost() ) { // Drop any clients that failed to migrate
for ( int i = m_Remote.Count()-1; i >= 0; --i ) { ClientDropped( m_Remote[i] ); }
// Update the lobby to show the new host
SendPlayerInfoToLobby( &m_Local, 0 );
// X360TBD: Figure out what state we should be in
int newState = m_PreMigrateState; switch( m_PreMigrateState ) { case MMSTATE_SESSION_CONNECTING: newState = MMSTATE_ACCEPTING_CONNECTIONS; break;
default: Warning( "Unhandled post-migrate state transition" ); }
// Don't use SwitchToState() to set our new state because when changing
// from a client to a host the state transition is usually invalid.
m_CurrentState = newState; } else { // Still a client, just restore our previous state
m_CurrentState = m_PreMigrateState; } }
void CMatchmaking::TestStats() {
}
|