250 lines
6.1 KiB
C++
250 lines
6.1 KiB
C++
//========= 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()
|
|
{
|
|
|
|
}
|