csgo-2018-source/matchmaking/mm_events.cpp
2021-07-24 21:11:47 -07:00

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;
}