1
This commit is contained in:
393
app/legion/networkmanager.cpp
Normal file
393
app/legion/networkmanager.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
//========= 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user