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.
249 lines
6.1 KiB
249 lines
6.1 KiB
//========= 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() |
|
{ |
|
|
|
}
|
|
|