1
This commit is contained in:
249
engine/matchmakingmigrate.cpp
Normal file
249
engine/matchmakingmigrate.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
//========= 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()
|
||||
{
|
||||
|
||||
}
|
Reference in New Issue
Block a user