From 3bf9df6b2785fa6d951086978a3e66f49427166a Mon Sep 17 00:00:00 2001 From: FluorescentCIAAfricanAmerican <0934gj3049fk@protonmail.com> Date: Wed, 22 Apr 2020 12:56:21 -0400 Subject: 1 --- engine/Session.cpp | 611 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 611 insertions(+) create mode 100644 engine/Session.cpp (limited to 'engine/Session.cpp') 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(); +} + -- cgit v1.2.3