222 lines
5.0 KiB
C++
222 lines
5.0 KiB
C++
//===== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//===========================================================================//
|
|
|
|
#include "mm_events.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
CMatchEventsSubscription::CMatchEventsSubscription() :
|
|
m_bAllowNestedBroadcasts( false ),
|
|
m_bBroadcasting( false )
|
|
{
|
|
;
|
|
}
|
|
|
|
CMatchEventsSubscription::~CMatchEventsSubscription()
|
|
{
|
|
;
|
|
}
|
|
|
|
static CMatchEventsSubscription g_MatchEventsSubscription;
|
|
CMatchEventsSubscription *g_pMatchEventsSubscription = &g_MatchEventsSubscription;
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
|
|
void CMatchEventsSubscription::Subscribe( IMatchEventsSink *pSink )
|
|
{
|
|
if ( !pSink )
|
|
return;
|
|
|
|
int idx = m_arrSinks.Find( pSink );
|
|
if ( m_arrSinks.IsValidIndex( idx ) )
|
|
{
|
|
Assert( m_arrRefCount.IsValidIndex( idx ) );
|
|
Assert( m_arrRefCount[ idx ] > 0 );
|
|
|
|
++ m_arrRefCount[ idx ];
|
|
}
|
|
else
|
|
{
|
|
m_arrSinks.AddToTail( pSink );
|
|
m_arrRefCount.AddToTail( 1 );
|
|
|
|
Assert( m_arrSinks.Count() == m_arrRefCount.Count() );
|
|
}
|
|
}
|
|
|
|
void CMatchEventsSubscription::Unsubscribe( IMatchEventsSink *pSink )
|
|
{
|
|
if ( !pSink )
|
|
return;
|
|
|
|
int idx = m_arrSinks.Find( pSink );
|
|
Assert( m_arrSinks.IsValidIndex( idx ) );
|
|
if ( !m_arrSinks.IsValidIndex( idx ) )
|
|
return;
|
|
|
|
Assert( m_arrRefCount.IsValidIndex( idx ) );
|
|
Assert( m_arrRefCount[ idx ] > 0 );
|
|
|
|
-- m_arrRefCount[ idx ];
|
|
if ( m_arrRefCount[ idx ] <= 0 )
|
|
{
|
|
m_arrSinks.Remove( idx );
|
|
m_arrRefCount.Remove( idx );
|
|
|
|
Assert( m_arrSinks.Count() == m_arrRefCount.Count() );
|
|
|
|
// Update outstanding iterators that are beyond removal point
|
|
for ( int k = 0; k < m_arrIteratorsOutstanding.Count(); ++ k )
|
|
{
|
|
if ( m_arrIteratorsOutstanding[k] >= idx )
|
|
-- m_arrIteratorsOutstanding[k];
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMatchEventsSubscription::Shutdown()
|
|
{
|
|
m_bBroadcasting = true; // Blocks all BroadcastEvent calls from being dispatched!
|
|
}
|
|
|
|
void CMatchEventsSubscription::BroadcastEvent( KeyValues *pEvent )
|
|
{
|
|
//
|
|
// Network raw packet decryption
|
|
//
|
|
if ( !Q_stricmp( "OnNetLanConnectionlessPacket", pEvent->GetName() ) )
|
|
{
|
|
if ( void * pRawPacket = pEvent->GetPtr( "rawpkt" ) )
|
|
{
|
|
netpacket_t *pkt = ( netpacket_t * ) pRawPacket;
|
|
pEvent->deleteThis();
|
|
|
|
g_pConnectionlessLanMgr->ProcessConnectionlessPacket( pkt );
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Broadcasting events is reliable even when subscribers get added
|
|
// or removed during broadcasts, or even broadcast nested events.
|
|
//
|
|
// Nested broadcasts are not allowed because it messes up the perception
|
|
// of event timeline by external listeners, nested broadcast is enqueued
|
|
// instead and broadcast after the original event has been broadcast to
|
|
// all subscribers.
|
|
//
|
|
|
|
if ( m_bBroadcasting )
|
|
{
|
|
if ( !m_bAllowNestedBroadcasts )
|
|
{
|
|
m_arrQueuedEvents.AddToTail( pEvent );
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_bBroadcasting = true;
|
|
|
|
KeyValues::AutoDelete autoDeleteEvent( pEvent );
|
|
m_arrSentEvents.AddToHead( pEvent );
|
|
|
|
// Internally events are cracked before external subscribers
|
|
g_pMMF->OnEvent( pEvent );
|
|
|
|
// iterate subscribers
|
|
for ( m_arrIteratorsOutstanding.AddToTail( 0 );
|
|
m_arrIteratorsOutstanding.Tail() < m_arrSinks.Count();
|
|
++ m_arrIteratorsOutstanding.Tail() )
|
|
{
|
|
int i = m_arrIteratorsOutstanding.Tail();
|
|
IMatchEventsSink *pSink = m_arrSinks[ i ];
|
|
|
|
Assert( m_arrRefCount.IsValidIndex( i ) );
|
|
Assert( m_arrRefCount[i] > 0 );
|
|
Assert( pSink );
|
|
|
|
pSink->OnEvent( pEvent );
|
|
}
|
|
m_arrIteratorsOutstanding.RemoveMultipleFromTail( 1 );
|
|
|
|
m_bBroadcasting = false;
|
|
|
|
//
|
|
// Broadcast queued events
|
|
//
|
|
if ( m_arrQueuedEvents.Count() > 0 )
|
|
{
|
|
KeyValues *pQueued = m_arrQueuedEvents.Head();
|
|
m_arrQueuedEvents.RemoveMultipleFromHead( 1 );
|
|
BroadcastEvent( pQueued );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// No more queued events left, clean up registered event data
|
|
//
|
|
for ( int k = 0; k < m_arrEventData.Count(); ++ k )
|
|
{
|
|
KeyValues *pRegistered = m_arrEventData[k];
|
|
pRegistered->deleteThis();
|
|
}
|
|
m_arrEventData.Purge();
|
|
m_arrSentEvents.Purge();
|
|
}
|
|
|
|
void CMatchEventsSubscription::RegisterEventData( KeyValues *pEventData )
|
|
{
|
|
Assert( pEventData );
|
|
if ( !pEventData )
|
|
return;
|
|
|
|
Assert( m_bBroadcasting );
|
|
|
|
char const *szEventDataKey = pEventData->GetName();
|
|
Assert( szEventDataKey && *szEventDataKey );
|
|
if ( !szEventDataKey || !*szEventDataKey )
|
|
return;
|
|
|
|
for ( int k = 0; k < m_arrEventData.Count(); ++ k )
|
|
{
|
|
KeyValues *&pRegistered = m_arrEventData[k];
|
|
if ( !Q_stricmp( szEventDataKey, pRegistered->GetName() ) )
|
|
{
|
|
pRegistered->deleteThis();
|
|
pRegistered = pEventData;
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_arrEventData.AddToTail( pEventData );
|
|
}
|
|
|
|
KeyValues * CMatchEventsSubscription::GetEventData( char const *szEventDataKey )
|
|
{
|
|
Assert( m_bBroadcasting );
|
|
|
|
for ( int k = 0; k < m_arrEventData.Count(); ++ k )
|
|
{
|
|
KeyValues *pRegistered = m_arrEventData[k];
|
|
if ( !Q_stricmp( szEventDataKey, pRegistered->GetName() ) )
|
|
return pRegistered;
|
|
}
|
|
|
|
for ( int k = 0; k < m_arrSentEvents.Count(); ++ k )
|
|
{
|
|
KeyValues *pRegistered = m_arrSentEvents[k];
|
|
if ( !Q_stricmp( szEventDataKey, pRegistered->GetName() ) )
|
|
return pRegistered;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|