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.
393 lines
12 KiB
393 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: The main manager of the networking code in the game |
|
// |
|
// $Revision: $ |
|
// $NoKeywords: $ |
|
//===========================================================================// |
|
|
|
#include "networkmanager.h" |
|
#include "legion.h" |
|
#include "networksystem/inetworkmessage.h" |
|
#include "tier1/bitbuf.h" |
|
#include "inetworkmessagelistener.h" |
|
#include "tier0/icommandline.h" |
|
#include "tier2/tier2.h" |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Singleton accessor |
|
//----------------------------------------------------------------------------- |
|
static CNetworkManager s_NetworkManager; |
|
extern CNetworkManager *g_pNetworkManager = &s_NetworkManager; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Static members. |
|
// NOTE: Do *not* set this to 0; it could cause us to lose some registered |
|
// menus since that list is set up during construction |
|
//----------------------------------------------------------------------------- |
|
INetworkMessageFactory *CNetworkManager::m_pFirstFactory; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Call to register methods to register network messages |
|
//----------------------------------------------------------------------------- |
|
INetworkMessageFactory *CNetworkManager::RegisterNetworkMessage( INetworkMessageFactory *pNetworkMessageFactory ) |
|
{ |
|
// NOTE: This method is expected to be called during global constructor |
|
// time, so it must not require any global constructors to be called to work |
|
INetworkMessageFactory *pPrevFactory = m_pFirstFactory; |
|
m_pFirstFactory = pNetworkMessageFactory; |
|
return pPrevFactory; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Init, shutdown |
|
//----------------------------------------------------------------------------- |
|
bool CNetworkManager::Init() |
|
{ |
|
m_bIsClient = m_bIsServer = false; |
|
m_pClientToServerConnection = NULL; |
|
|
|
// Make a listener array for each message type |
|
|
|
// Register all network messages |
|
INetworkMessageFactory *pFactory; |
|
for ( pFactory = m_pFirstFactory; pFactory; pFactory = pFactory->GetNextFactory() ) |
|
{ |
|
INetworkMessage *pNetworkMessage = pFactory->CreateNetworkMessage(); |
|
g_pNetworkSystem->RegisterMessage( pNetworkMessage ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void CNetworkManager::Shutdown() |
|
{ |
|
ShutdownClient(); |
|
ShutdownServer(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Start a server up |
|
//----------------------------------------------------------------------------- |
|
bool CNetworkManager::StartServer( unsigned short nServerListenPort ) |
|
{ |
|
ShutdownServer( ); |
|
if ( nServerListenPort == LEGION_DEFAULT_SERVER_PORT ) |
|
{ |
|
nServerListenPort = CommandLine()->ParmValue( "-serverport", NETWORKSYSTEM_DEFAULT_SERVER_PORT ); |
|
} |
|
m_bIsServer = g_pNetworkSystem->StartServer( nServerListenPort ); |
|
return m_bIsServer; |
|
} |
|
|
|
void CNetworkManager::ShutdownServer( ) |
|
{ |
|
if ( m_bIsServer ) |
|
{ |
|
g_pNetworkSystem->ShutdownServer( ); |
|
m_bIsServer = false; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Start a client up |
|
//----------------------------------------------------------------------------- |
|
bool CNetworkManager::StartClient( unsigned short nClientListenPort ) |
|
{ |
|
ShutdownClient( ); |
|
|
|
if ( nClientListenPort == LEGION_DEFAULT_CLIENT_PORT ) |
|
{ |
|
nClientListenPort = CommandLine()->ParmValue( "-clientport", NETWORKSYSTEM_DEFAULT_CLIENT_PORT ); |
|
} |
|
|
|
m_bIsClient = g_pNetworkSystem->StartClient( nClientListenPort ); |
|
return m_bIsClient; |
|
} |
|
|
|
void CNetworkManager::ShutdownClient( ) |
|
{ |
|
if ( m_bIsClient ) |
|
{ |
|
DisconnectClientFromServer(); |
|
g_pNetworkSystem->ShutdownClient( ); |
|
m_bIsClient = false; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Connects/disconnects the client to a server |
|
//----------------------------------------------------------------------------- |
|
bool CNetworkManager::ConnectClientToServer( const char *pServerName, unsigned short nServerListenPort ) |
|
{ |
|
DisconnectClientFromServer(); |
|
if ( !IsClient() ) |
|
return false; |
|
|
|
if ( nServerListenPort == LEGION_DEFAULT_SERVER_PORT ) |
|
{ |
|
nServerListenPort = CommandLine()->ParmValue( "-serverport", NETWORKSYSTEM_DEFAULT_SERVER_PORT ); |
|
} |
|
m_pClientToServerConnection = g_pNetworkSystem->ConnectClientToServer( pServerName, nServerListenPort ); |
|
return ( m_pClientToServerConnection != NULL ); |
|
} |
|
|
|
void CNetworkManager::DisconnectClientFromServer( ) |
|
{ |
|
if ( m_pClientToServerConnection ) |
|
{ |
|
g_pNetworkSystem->DisconnectClientFromServer( m_pClientToServerConnection ); |
|
m_pClientToServerConnection = NULL; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Start up a game where the local player is playing |
|
//----------------------------------------------------------------------------- |
|
bool CNetworkManager::HostGame() |
|
{ |
|
if ( !StartServer() ) |
|
return false; |
|
|
|
if ( !StartClient() ) |
|
{ |
|
ShutdownServer(); |
|
return false; |
|
} |
|
|
|
if ( !ConnectClientToServer( "localhost" ) ) |
|
{ |
|
ShutdownClient(); |
|
ShutdownServer(); |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void CNetworkManager::StopHostingGame() |
|
{ |
|
ShutdownClient(); |
|
ShutdownServer(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Are we a client?/Are we a server? (we can be both) |
|
//----------------------------------------------------------------------------- |
|
bool CNetworkManager::IsClient() |
|
{ |
|
return m_bIsClient; |
|
} |
|
|
|
bool CNetworkManager::IsServer() |
|
{ |
|
return m_bIsServer; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// If we are a client, are we connected to the server? |
|
//----------------------------------------------------------------------------- |
|
bool CNetworkManager::IsClientConnected() |
|
{ |
|
return m_bIsClient && ( m_pClientToServerConnection != NULL ) && ( m_pClientToServerConnection->GetConnectionState() == CONNECTION_STATE_CONNECTED ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Post a network message to the server |
|
//----------------------------------------------------------------------------- |
|
void CNetworkManager::PostClientToServerMessage( INetworkMessage *pMessage ) |
|
{ |
|
if ( IsClientConnected() ) |
|
{ |
|
m_pClientToServerConnection->AddNetMsg( pMessage ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Broadcast a network message to all clients |
|
//----------------------------------------------------------------------------- |
|
void CNetworkManager::BroadcastServerToClientMessage( INetworkMessage *pMessage ) |
|
{ |
|
if ( IsServer() ) |
|
{ |
|
int nCount = m_ServerToClientConnection.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
m_ServerToClientConnection[i]->AddNetMsg( pMessage ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Add, remove network message listeners |
|
//----------------------------------------------------------------------------- |
|
void CNetworkManager::AddListener( NetworkMessageRoute_t route, int nGroup, int nType, INetworkMessageListener *pListener ) |
|
{ |
|
CUtlVector< CUtlVector< CUtlVector < INetworkMessageListener* > > > &listeners = m_Listeners[ route ]; |
|
if ( listeners.Count() <= nGroup ) |
|
{ |
|
listeners.AddMultipleToTail( nGroup - listeners.Count() + 1 ); |
|
} |
|
|
|
if ( listeners[nGroup].Count() <= nType ) |
|
{ |
|
listeners[nGroup].AddMultipleToTail( nType - listeners[nGroup].Count() + 1 ); |
|
} |
|
|
|
Assert( listeners[nGroup][nType].Find( pListener ) < 0 ); |
|
listeners[nGroup][nType].AddToTail( pListener ); |
|
} |
|
|
|
void CNetworkManager::RemoveListener( NetworkMessageRoute_t route, int nGroup, int nType, INetworkMessageListener *pListener ) |
|
{ |
|
CUtlVector< CUtlVector< CUtlVector < INetworkMessageListener* > > > &listeners = m_Listeners[ route ]; |
|
if ( listeners.Count() > nGroup ) |
|
{ |
|
if( listeners[nGroup].Count() > nType ) |
|
{ |
|
// Maintain order of listeners (not sure if it matters) |
|
listeners[nGroup][nType].FindAndRemove( pListener ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Notifies listeners about a network message |
|
//----------------------------------------------------------------------------- |
|
void CNetworkManager::NotifyListeners( NetworkMessageRoute_t route, INetworkMessage *pMessage ) |
|
{ |
|
CUtlVector< CUtlVector< CUtlVector < INetworkMessageListener* > > > &listeners = m_Listeners[ route ]; |
|
|
|
// based on id, search for installed listeners |
|
int nGroup = pMessage->GetGroup(); |
|
if ( listeners.Count() > nGroup ) |
|
{ |
|
int nType = pMessage->GetType(); |
|
if ( listeners[nGroup].Count() > nType ) |
|
{ |
|
CUtlVector< INetworkMessageListener* > &list = listeners[nGroup][nType]; |
|
int nCount = list.Count(); |
|
for ( int i = 0; i < nCount; ++i ) |
|
{ |
|
list[i]->OnNetworkMessage( route, pMessage ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Process messages received by the client |
|
//----------------------------------------------------------------------------- |
|
void CNetworkManager::ProcessClientMessages() |
|
{ |
|
NetworkEvent_t *pEvent = g_pNetworkSystem->FirstNetworkEvent(); |
|
for ( ; pEvent; pEvent = g_pNetworkSystem->NextNetworkEvent( ) ) |
|
{ |
|
switch ( pEvent->m_nType ) |
|
{ |
|
/* |
|
case NETWORK_EVENT_CONNECTED: |
|
{ |
|
NetworkConnectionEvent_t* pConnectEvent = static_cast<NetworkConnectionEvent_t*>( pEvent ); |
|
m_pClientToServerConnection = pConnectEvent->m_pChannel; |
|
} |
|
break; |
|
|
|
case NETWORK_EVENT_DISCONNECTED: |
|
{ |
|
NetworkDisconnectionEvent_t* pDisconnectEvent = static_cast<NetworkDisconnectionEvent_t*>( pEvent ); |
|
Assert( m_pClientToServerConnection == pDisconnectEvent->m_pChannel ); |
|
if ( m_pClientToServerConnection == pDisconnectEvent->m_pChannel ) |
|
{ |
|
m_pClientToServerConnection = NULL; |
|
} |
|
} |
|
break; |
|
*/ |
|
|
|
case NETWORK_EVENT_MESSAGE_RECEIVED: |
|
{ |
|
NetworkMessageReceivedEvent_t* pPacketEvent = static_cast<NetworkMessageReceivedEvent_t*>( pEvent ); |
|
NotifyListeners( NETWORK_MESSAGE_SERVER_TO_CLIENT, pPacketEvent->m_pNetworkMessage ); |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Process messages received by the server |
|
//----------------------------------------------------------------------------- |
|
void CNetworkManager::ProcessServerMessages() |
|
{ |
|
NetworkEvent_t *pEvent = g_pNetworkSystem->FirstNetworkEvent(); |
|
for ( ; pEvent; pEvent = g_pNetworkSystem->NextNetworkEvent( ) ) |
|
{ |
|
switch ( pEvent->m_nType ) |
|
{ |
|
case NETWORK_EVENT_CONNECTED: |
|
{ |
|
NetworkConnectionEvent_t* pConnectEvent = static_cast<NetworkConnectionEvent_t*>( pEvent ); |
|
m_ServerToClientConnection.AddToTail( pConnectEvent->m_pChannel ); |
|
} |
|
break; |
|
|
|
case NETWORK_EVENT_DISCONNECTED: |
|
{ |
|
NetworkDisconnectionEvent_t* pDisconnectEvent = static_cast<NetworkDisconnectionEvent_t*>( pEvent ); |
|
m_ServerToClientConnection.FindAndRemove( pDisconnectEvent->m_pChannel ); |
|
} |
|
break; |
|
|
|
case NETWORK_EVENT_MESSAGE_RECEIVED: |
|
{ |
|
NetworkMessageReceivedEvent_t* pPacketEvent = static_cast<NetworkMessageReceivedEvent_t*>( pEvent ); |
|
NotifyListeners( NETWORK_MESSAGE_CLIENT_TO_SERVER, pPacketEvent->m_pNetworkMessage ); |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Per-frame update |
|
//----------------------------------------------------------------------------- |
|
void CNetworkManager::Update( ) |
|
{ |
|
if ( IsClient() ) |
|
{ |
|
g_pNetworkSystem->ClientSendMessages(); |
|
} |
|
|
|
if ( IsServer() ) |
|
{ |
|
g_pNetworkSystem->ServerReceiveMessages(); |
|
ProcessServerMessages(); |
|
g_pNetworkSystem->ServerSendMessages(); |
|
} |
|
|
|
if ( IsClient() ) |
|
{ |
|
g_pNetworkSystem->ClientReceiveMessages(); |
|
ProcessClientMessages(); |
|
} |
|
} |
|
|
|
|
|
|