summaryrefslogtreecommitdiff
path: root/engine/Session.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/Session.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'engine/Session.cpp')
-rw-r--r--engine/Session.cpp611
1 files changed, 611 insertions, 0 deletions
diff --git a/engine/Session.cpp b/engine/Session.cpp
new file mode 100644
index 0000000..c0e0018
--- /dev/null
+++ b/engine/Session.cpp
@@ -0,0 +1,611 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "Session.h"
+#include "strtools.h"
+#include "matchmaking.h"
+#include "utllinkedlist.h"
+#include "tslist.h"
+#include "hl2orange.spa.h"
+#include "dbg.h"
+
+#ifdef IS_WINDOWS_PC
+#include "winlite.h" // for CloseHandle()
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern IXboxSystem *g_pXboxSystem;
+
+#define ASYNC_OK 0
+#define ASYNC_FAIL 1
+
+//-----------------------------------------------------------------------------
+// Purpose: CSession class
+//-----------------------------------------------------------------------------
+CSession::CSession()
+{
+ m_pParent = NULL;
+ m_hSession = INVALID_HANDLE_VALUE;
+ m_SessionState = SESSION_STATE_NONE;
+ m_pRegistrationResults = NULL;
+
+ ResetSession();
+}
+
+CSession::~CSession()
+{
+ ResetSession();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reset a session to it's initial state
+//-----------------------------------------------------------------------------
+void CSession::ResetSession()
+{
+ // Cleanup first
+ switch( m_SessionState )
+ {
+ case SESSION_STATE_CREATING:
+ CancelCreateSession();
+ break;
+
+ case SESSION_STATE_MIGRATING:
+ // X360TBD:
+ break;
+ }
+
+ if ( m_hSession != INVALID_HANDLE_VALUE )
+ {
+ Msg( "ResetSession: Destroying current session.\n" );
+
+ DestroySession();
+ m_hSession = INVALID_HANDLE_VALUE;
+ }
+
+ SwitchToState( SESSION_STATE_NONE );
+
+ m_bIsHost = false;
+ m_bIsArbitrated = false;
+ m_bUsingQoS = false;
+ m_bIsSystemLink = false;
+ Q_memset( &m_nPlayerSlots, 0, sizeof( m_nPlayerSlots ) );
+ Q_memset( &m_SessionInfo, 0, sizeof( m_SessionInfo ) );
+
+ if ( m_pRegistrationResults )
+ {
+ delete m_pRegistrationResults;
+ }
+
+ m_nSessionFlags = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set session contexts and properties
+//-----------------------------------------------------------------------------
+void CSession::SetContext( const uint nContextId, const uint nContextValue, const bool bAsync )
+{
+ g_pXboxSystem->UserSetContext( XBX_GetPrimaryUserId(), nContextId, nContextValue, bAsync );
+}
+void CSession::SetProperty( const uint nPropertyId, const uint cbValue, const void *pvValue, const bool bAsync )
+{
+ g_pXboxSystem->UserSetProperty( XBX_GetPrimaryUserId(), nPropertyId, cbValue, pvValue, bAsync );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Send a notification to GameUI
+//-----------------------------------------------------------------------------
+void CSession::SendNotification( SESSION_NOTIFY notification )
+{
+ Assert( m_pParent );
+ m_pParent->SessionNotification( notification );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update the number of player slots filled
+//-----------------------------------------------------------------------------
+void CSession::UpdateSlots( const CClientInfo *pClient, bool bAddPlayers )
+{
+ int cPlayers = pClient->m_cPlayers;
+ if ( bAddPlayers )
+ {
+ if ( pClient->m_bInvited )
+ {
+ // Fill private slots first, then overflow into public slots
+ m_nPlayerSlots[SLOTS_FILLEDPRIVATE] += cPlayers;
+ pClient->m_numPrivateSlotsUsed = cPlayers;
+ cPlayers = 0;
+ if ( m_nPlayerSlots[SLOTS_FILLEDPRIVATE] > m_nPlayerSlots[SLOTS_TOTALPRIVATE] )
+ {
+ cPlayers = m_nPlayerSlots[SLOTS_FILLEDPRIVATE] - m_nPlayerSlots[SLOTS_TOTALPRIVATE];
+ pClient->m_numPrivateSlotsUsed -= cPlayers;
+ m_nPlayerSlots[SLOTS_FILLEDPRIVATE] = m_nPlayerSlots[SLOTS_TOTALPRIVATE];
+ }
+ }
+ m_nPlayerSlots[SLOTS_FILLEDPUBLIC] += cPlayers;
+ if ( m_nPlayerSlots[SLOTS_FILLEDPUBLIC] > m_nPlayerSlots[SLOTS_TOTALPUBLIC] )
+ {
+ //Handle error
+ Warning( "Too many players!\n" );
+ }
+ }
+ else
+ {
+ // The cast to 'int' is needed since otherwise underflow will wrap around to very large
+ // numbers and the 'max' macro will do nothing.
+ m_nPlayerSlots[SLOTS_FILLEDPRIVATE] = max( 0, (int)( m_nPlayerSlots[SLOTS_FILLEDPRIVATE] - pClient->m_numPrivateSlotsUsed ) );
+ m_nPlayerSlots[SLOTS_FILLEDPUBLIC] = max( 0, (int)( m_nPlayerSlots[SLOTS_FILLEDPUBLIC] - ( pClient->m_cPlayers - pClient->m_numPrivateSlotsUsed ) ) );
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Join players on the local client
+//-----------------------------------------------------------------------------
+void CSession::JoinLocal( const CClientInfo *pClient )
+{
+ uint nUserIndex[MAX_PLAYERS_PER_CLIENT] = {0};
+ bool bPrivate[MAX_PLAYERS_PER_CLIENT] = {0};
+
+ for( int i = 0; i < pClient->m_cPlayers; ++i )
+ {
+ nUserIndex[i] = pClient->m_iControllers[i];
+ bPrivate[i] = pClient->m_bInvited;
+ }
+
+ // X360TBD: Make async?
+ uint ret = g_pXboxSystem->SessionJoinLocal( m_hSession, pClient->m_cPlayers, nUserIndex, bPrivate, false );
+ if ( ret != ERROR_SUCCESS )
+ {
+ // Handle error
+ Warning( "Failed to add local players\n" );
+ }
+ else
+ {
+ UpdateSlots( pClient, true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Join players on a remote client
+//-----------------------------------------------------------------------------
+void CSession::JoinRemote( const CClientInfo *pClient )
+{
+ XUID xuids[MAX_PLAYERS_PER_CLIENT] = {0};
+ bool bPrivate[MAX_PLAYERS_PER_CLIENT] = {0};
+
+ for( int i = 0; i < pClient->m_cPlayers; ++i )
+ {
+ xuids[i] = pClient->m_xuids[i];
+ bPrivate[i] = pClient->m_bInvited;
+ }
+
+ // X360TBD: Make async?
+ uint ret = g_pXboxSystem->SessionJoinRemote( m_hSession, pClient->m_cPlayers, xuids, bPrivate, false );
+ if ( ret != ERROR_SUCCESS )
+ {
+ // Handle error
+ Warning( "Join Remote Error\n" );
+ }
+ else
+ {
+ UpdateSlots( pClient, true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove players on the local client
+//-----------------------------------------------------------------------------
+void CSession::RemoveLocal( const CClientInfo *pClient )
+{
+ uint nUserIndex[MAX_PLAYERS_PER_CLIENT] = {0};
+
+ for( int i = 0; i < pClient->m_cPlayers; ++i )
+ {
+ nUserIndex[i] = pClient->m_iControllers[i];
+ }
+
+ // X360TBD: Make async?
+ uint ret = g_pXboxSystem->SessionLeaveLocal( m_hSession, pClient->m_cPlayers, nUserIndex, false );
+ if ( ret != ERROR_SUCCESS )
+ {
+ // Handle error
+ Warning( "Failed to remove local players\n" );
+ }
+ else
+ {
+ UpdateSlots( pClient, false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove players on a remote client
+//-----------------------------------------------------------------------------
+void CSession::RemoveRemote( const CClientInfo *pClient )
+{
+ XUID xuids[MAX_PLAYERS_PER_CLIENT] = {0};
+
+ for( int i = 0; i < pClient->m_cPlayers; ++i )
+ {
+ xuids[i] = pClient->m_xuids[i];
+ }
+
+ // X360TBD: Make async?
+ uint ret = g_pXboxSystem->SessionLeaveRemote( m_hSession, pClient->m_cPlayers, xuids, false );
+ if ( ret != ERROR_SUCCESS )
+ {
+ // Handle error
+ Warning( "Failed to remove remote players\n" );
+ }
+ else
+ {
+ UpdateSlots( pClient, false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a new session
+//-----------------------------------------------------------------------------
+bool CSession::CreateSession()
+{
+ if( INVALID_HANDLE_VALUE != m_hSession )
+ {
+ Warning( "CreateSession called on existing session!" );
+ DestroySession();
+ m_hSession = INVALID_HANDLE_VALUE;
+ }
+
+ uint flags = m_nSessionFlags;
+ if( m_bIsHost )
+ {
+ flags |= XSESSION_CREATE_HOST;
+ }
+
+ if ( flags & XSESSION_CREATE_USES_ARBITRATION )
+ {
+ m_bIsArbitrated = true;
+ }
+
+ m_hCreateHandle = g_pXboxSystem->CreateAsyncHandle();
+
+ // Create the session
+ uint ret = g_pXboxSystem->CreateSession( flags,
+ XBX_GetPrimaryUserId(),
+ m_nPlayerSlots[SLOTS_TOTALPUBLIC],
+ m_nPlayerSlots[SLOTS_TOTALPRIVATE],
+ &m_SessionNonce,
+ &m_SessionInfo,
+ &m_hSession,
+ true,
+ &m_hCreateHandle );
+
+ if( ret != ERROR_SUCCESS && ret != ERROR_IO_PENDING )
+ {
+ Warning( "XSessionCreate failed with error %d\n", ret );
+ return false;
+ }
+
+ SwitchToState( SESSION_STATE_CREATING );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check for completion while creating a new session
+//-----------------------------------------------------------------------------
+void CSession::UpdateCreating()
+{
+ DWORD ret = g_pXboxSystem->GetOverlappedResult( m_hCreateHandle, NULL, false );
+ if ( ret == ERROR_IO_INCOMPLETE )
+ {
+ // Still waiting
+ return;
+ }
+ else
+ {
+ SESSION_STATE nextState = SESSION_STATE_IDLE;
+
+ // Operation completed
+ SESSION_NOTIFY notification = IsHost() ? SESSION_NOTIFY_CREATED_HOST : SESSION_NOTIFY_CREATED_CLIENT;
+ if ( ret != ERROR_SUCCESS )
+ {
+ Warning( "CSession: CreateSession failed. Error %d\n", ret );
+
+ nextState = SESSION_STATE_NONE;
+ notification = SESSION_NOTIFY_FAIL_CREATE;
+ }
+
+ g_pXboxSystem->ReleaseAsyncHandle( m_hCreateHandle );
+
+ SendNotification( notification );
+ SwitchToState( nextState );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Cancel async session creation
+//-----------------------------------------------------------------------------
+void CSession::CancelCreateSession()
+{
+ if ( m_SessionState != SESSION_STATE_CREATING )
+ return;
+
+ g_pXboxSystem->CancelOverlappedOperation( &m_hCreateHandle );
+ g_pXboxSystem->ReleaseAsyncHandle( m_hCreateHandle );
+
+#ifndef POSIX
+ if( INVALID_HANDLE_VALUE != m_hSession )
+ {
+ CloseHandle( m_hSession );
+ m_hSession = INVALID_HANDLE_VALUE;
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Close an existing session
+//-----------------------------------------------------------------------------
+void CSession::DestroySession()
+{
+ // TODO: Make this async
+ uint ret = g_pXboxSystem->DeleteSession( m_hSession, false );
+ if ( ret != ERROR_SUCCESS )
+ {
+ Warning( "Failed to delete session with error %d.\n", ret );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Register for arbritation in a ranked match
+//-----------------------------------------------------------------------------
+void CSession::RegisterForArbitration()
+{
+ uint bytes = 0;
+ m_pRegistrationResults = NULL;
+
+ // Call once to determine size of results buffer
+ int ret = g_pXboxSystem->SessionArbitrationRegister( m_hSession, 0, m_SessionNonce, &bytes, NULL, false );
+ if ( ret != ERROR_INSUFFICIENT_BUFFER )
+ {
+ Warning( "Failed registering for arbitration\n" );
+ return;
+ }
+
+ m_pRegistrationResults = (XSESSION_REGISTRATION_RESULTS*)new byte[ bytes ];
+
+ m_hRegisterHandle = g_pXboxSystem->CreateAsyncHandle();
+
+ ret = g_pXboxSystem->SessionArbitrationRegister( m_hSession, 0, m_SessionNonce, &bytes, m_pRegistrationResults, true, &m_hRegisterHandle );
+ if( ret != ERROR_IO_PENDING )
+ {
+ Warning( "Failed registering for arbitration\n" );
+ }
+
+ m_SessionState = SESSION_STATE_REGISTERING;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check for completion of arbitration registration
+//-----------------------------------------------------------------------------
+void CSession::UpdateRegistering()
+{
+ DWORD ret = g_pXboxSystem->GetOverlappedResult( m_hRegisterHandle, NULL, false );
+ if ( ret == ERROR_IO_INCOMPLETE )
+ {
+ // Still waiting
+ return;
+ }
+ else
+ {
+ SESSION_STATE nextState = SESSION_STATE_IDLE;
+
+ // Operation completed
+ SESSION_NOTIFY notification = SESSION_NOTIFY_REGISTER_COMPLETED;
+ if ( ret != ERROR_SUCCESS )
+ {
+ Warning( "CSession: Registration failed. Error %d\n", ret );
+
+ nextState = SESSION_STATE_NONE;
+ notification = SESSION_NOTIFY_FAIL_REGISTER;
+ }
+
+ g_pXboxSystem->ReleaseAsyncHandle( m_hRegisterHandle );
+
+ SendNotification( notification );
+ SwitchToState( nextState );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// 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;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check for completion while migrating a session
+//-----------------------------------------------------------------------------
+void CSession::UpdateMigrating()
+{
+ DWORD ret = g_pXboxSystem->GetOverlappedResult( m_hMigrateHandle, NULL, false );
+ if ( ret == ERROR_IO_INCOMPLETE )
+ {
+ // Still waiting
+ return;
+ }
+ else
+ {
+ SESSION_STATE nextState = SESSION_STATE_IDLE;
+
+ // Operation completed
+ SESSION_NOTIFY notification = SESSION_NOTIFY_MIGRATION_COMPLETED;
+ if ( ret != ERROR_SUCCESS )
+ {
+ Warning( "CSession: MigrateSession failed. Error %d\n", ret );
+
+ nextState = SESSION_STATE_NONE;
+ notification = SESSION_NOTIFY_FAIL_MIGRATE;
+ }
+
+ g_pXboxSystem->ReleaseAsyncHandle( m_hMigrateHandle );
+
+ SendNotification( notification );
+ SwitchToState( nextState );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Change state
+//-----------------------------------------------------------------------------
+void CSession::SwitchToState( SESSION_STATE newState )
+{
+ m_SessionState = newState;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Per-frame update
+//-----------------------------------------------------------------------------
+void CSession::RunFrame()
+{
+ switch( m_SessionState )
+ {
+ case SESSION_STATE_CREATING:
+ UpdateCreating();
+ break;
+
+ case SESSION_STATE_REGISTERING:
+ UpdateRegistering();
+ break;
+
+ case SESSION_STATE_MIGRATING:
+ UpdateMigrating();
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Accessors
+//-----------------------------------------------------------------------------
+HANDLE CSession::GetSessionHandle()
+{
+ return m_hSession;
+}
+void CSession::SetSessionInfo( XSESSION_INFO *pInfo )
+{
+ memcpy( &m_SessionInfo, pInfo, sizeof( XSESSION_INFO ) );
+}
+void CSession::SetNewSessionInfo( XSESSION_INFO *pInfo )
+{
+ memcpy( &m_NewSessionInfo, pInfo, sizeof( XSESSION_INFO ) );
+}
+void CSession::GetSessionInfo( XSESSION_INFO *pInfo )
+{
+ Assert( pInfo );
+ memcpy( pInfo, &m_SessionInfo, sizeof( XSESSION_INFO ) );
+}
+void CSession::GetNewSessionInfo( XSESSION_INFO *pInfo )
+{
+ Assert( pInfo );
+ memcpy( pInfo, &m_NewSessionInfo, sizeof( XSESSION_INFO ) );
+}
+void CSession::SetSessionNonce( int64 nonce )
+{
+ m_SessionNonce = nonce;
+}
+uint64 CSession::GetSessionNonce()
+{
+ return m_SessionNonce;
+}
+XNKID CSession::GetSessionId()
+{
+ return m_SessionInfo.sessionID;
+}
+void CSession::SetSessionSlots(unsigned int nSlot, unsigned int nPlayers)
+{
+ Assert( nSlot < SLOTS_LAST );
+ m_nPlayerSlots[nSlot] = nPlayers;
+}
+unsigned int CSession::GetSessionSlots( unsigned int nSlot )
+{
+ Assert( nSlot < SLOTS_LAST );
+ return m_nPlayerSlots[nSlot];
+}
+void CSession::SetSessionFlags( uint flags )
+{
+ m_nSessionFlags = flags;
+}
+uint CSession::GetSessionFlags()
+{
+ return m_nSessionFlags;
+}
+int CSession::GetPlayerCount()
+{
+ return m_nPlayerSlots[SLOTS_FILLEDPRIVATE] + m_nPlayerSlots[SLOTS_FILLEDPUBLIC];
+}
+void CSession::SetFlag( uint nFlag )
+{
+ m_nSessionFlags |= nFlag;
+}
+void CSession::SetIsHost( bool bHost )
+{
+ m_bIsHost = bHost;
+}
+void CSession::SetIsSystemLink( bool bSystemLink )
+{
+ m_bIsSystemLink = bSystemLink;
+}
+void CSession::SetOwnerId( uint id )
+{
+ m_nOwnerId = id;
+}
+bool CSession::IsHost()
+{
+ return m_bIsHost;
+}
+bool CSession::IsFull()
+{
+ return ( GetSessionSlots( SLOTS_TOTALPRIVATE ) == GetSessionSlots( SLOTS_FILLEDPRIVATE ) &&
+ GetSessionSlots( SLOTS_TOTALPUBLIC ) == GetSessionSlots( SLOTS_FILLEDPUBLIC ) );
+}
+bool CSession::IsArbitrated()
+{
+ return m_bIsArbitrated;
+}
+bool CSession::IsSystemLink()
+{
+ return m_bIsSystemLink;
+}
+void CSession::SetParent( CMatchmaking *pParent )
+{
+ m_pParent = pParent;
+}
+double CSession::GetTime()
+{
+ return Plat_FloatTime();
+}
+