summaryrefslogtreecommitdiff
path: root/engine/GameEventManager.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/GameEventManager.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'engine/GameEventManager.cpp')
-rw-r--r--engine/GameEventManager.cpp921
1 files changed, 921 insertions, 0 deletions
diff --git a/engine/GameEventManager.cpp b/engine/GameEventManager.cpp
new file mode 100644
index 0000000..1d6d50f
--- /dev/null
+++ b/engine/GameEventManager.cpp
@@ -0,0 +1,921 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// GameEventManager.cpp: implementation of the CGameEventManager class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "GameEventManager.h"
+#include "filesystem_engine.h"
+#include "server.h"
+#include "client.h"
+#include "tier0/vprof.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+static CGameEventManager s_GameEventManager;
+CGameEventManager &g_GameEventManager = s_GameEventManager;
+
+static const char *s_GameEnventTypeMap[] =
+{ "local", // 0 : don't network this field
+ "string", // 1 : zero terminated ASCII string
+ "float", // 2 : float 32 bit
+ "long", // 3 : signed int 32 bit
+ "short", // 4 : signed int 16 bit
+ "byte", // 5 : unsigned int 8 bit
+ "bool", // 6 : unsigned int 1 bit
+ NULL };
+
+static ConVar net_showevents( "net_showevents", "0", FCVAR_CHEAT, "Dump game events to console (1=client only, 2=all)." );
+
+// Expose CVEngineServer to the engine.
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CGameEventManager, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2, s_GameEventManager );
+
+CGameEvent::CGameEvent( CGameEventDescriptor *descriptor )
+{
+ Assert( descriptor );
+ m_pDescriptor = descriptor;
+ m_pDataKeys = new KeyValues( descriptor->name );
+}
+
+CGameEvent::~CGameEvent()
+{
+ m_pDataKeys->deleteThis();
+}
+
+bool CGameEvent::GetBool( const char *keyName, bool defaultValue)
+{
+ return m_pDataKeys->GetInt( keyName, defaultValue ) != 0;
+}
+
+int CGameEvent::GetInt( const char *keyName, int defaultValue)
+{
+ return m_pDataKeys->GetInt( keyName, defaultValue );
+}
+
+float CGameEvent::GetFloat( const char *keyName, float defaultValue )
+{
+ return m_pDataKeys->GetFloat( keyName, defaultValue );
+}
+
+const char *CGameEvent::GetString( const char *keyName, const char *defaultValue )
+{
+ return m_pDataKeys->GetString( keyName, defaultValue );
+}
+
+void CGameEvent::SetBool( const char *keyName, bool value )
+{
+ m_pDataKeys->SetInt( keyName, value?1:0 );
+}
+
+void CGameEvent::SetInt( const char *keyName, int value )
+{
+ m_pDataKeys->SetInt( keyName, value );
+}
+
+void CGameEvent::SetFloat( const char *keyName, float value )
+{
+ m_pDataKeys->SetFloat( keyName, value );
+}
+
+void CGameEvent::SetString( const char *keyName, const char *value )
+{
+ m_pDataKeys->SetString( keyName, value );
+}
+
+bool CGameEvent::IsEmpty( const char *keyName )
+{
+ return m_pDataKeys->IsEmpty( keyName );
+}
+
+const char *CGameEvent::GetName() const
+{
+ return m_pDataKeys->GetName();
+}
+
+bool CGameEvent::IsLocal() const
+{
+ return m_pDescriptor->local;
+}
+
+bool CGameEvent::IsReliable() const
+{
+ return m_pDescriptor->reliable;
+}
+
+CGameEventManager::CGameEventManager()
+{
+ Reset();
+}
+
+CGameEventManager::~CGameEventManager()
+{
+ Reset();
+}
+
+bool CGameEventManager::Init()
+{
+ Reset();
+
+ LoadEventsFromFile( "resource/serverevents.res" );
+
+ return true;
+}
+
+void CGameEventManager::Shutdown()
+{
+ Reset();
+}
+
+void CGameEventManager::Reset()
+{
+ int number = m_GameEvents.Count();
+
+ for (int i = 0; i<number; i++)
+ {
+ CGameEventDescriptor &e = m_GameEvents.Element( i );
+
+ if ( e.keys )
+ {
+ e.keys->deleteThis(); // free the value keys
+ e.keys = NULL;
+ }
+
+ e.listeners.Purge(); // remove listeners
+ }
+
+ m_GameEvents.Purge();
+ m_Listeners.PurgeAndDeleteElements();
+ m_EventFiles.RemoveAll();
+ m_EventFileNames.RemoveAll();
+ m_bClientListenersChanged = true;
+
+ Assert( m_GameEvents.Count() == 0 );
+}
+
+bool CGameEventManager::HasClientListenersChanged( bool bReset /* = true */)
+{
+ if ( !m_bClientListenersChanged )
+ return false;
+
+ if ( bReset )
+ m_bClientListenersChanged = false;
+
+ return true;
+}
+
+void CGameEventManager::WriteEventList(SVC_GameEventList *msg)
+{
+ // reset event ids to -1 first
+
+ msg->m_nNumEvents = 0;
+
+ for (int i=0; i < m_GameEvents.Count(); i++ )
+ {
+ CGameEventDescriptor &descriptor = m_GameEvents[i];
+
+ if ( descriptor.local )
+ continue;
+
+ Assert( descriptor.eventid >= 0 && descriptor.eventid < MAX_EVENT_NUMBER );
+
+ msg->m_DataOut.WriteUBitLong( descriptor.eventid, MAX_EVENT_BITS );
+ msg->m_DataOut.WriteString( descriptor.name );
+
+ KeyValues *key = descriptor.keys->GetFirstSubKey();
+
+ while ( key )
+ {
+ int type = key->GetInt();
+
+ if ( type != TYPE_LOCAL )
+ {
+ msg->m_DataOut.WriteUBitLong( type, 3 );
+ msg->m_DataOut.WriteString( key->GetName() );
+ }
+
+ key = key->GetNextKey();
+ }
+
+ msg->m_DataOut.WriteUBitLong( TYPE_LOCAL, 3 ); // end marker
+
+ msg->m_nNumEvents++;
+ }
+}
+
+bool CGameEventManager::ParseEventList(SVC_GameEventList *msg)
+{
+ int i;
+
+ // reset eventids to -1 first
+ for ( i=0; i < m_GameEvents.Count(); i++ )
+ {
+ CGameEventDescriptor &descriptor = m_GameEvents[i];
+ descriptor.eventid = -1;
+ }
+
+ // map server event IDs
+ for (i = 0; i<msg->m_nNumEvents; i++)
+ {
+ int id = msg->m_DataIn.ReadUBitLong( MAX_EVENT_BITS );
+ char name[MAX_EVENT_NAME_LENGTH];
+ msg->m_DataIn.ReadString( name, sizeof(name) );
+
+ CGameEventDescriptor *descriptor = GetEventDescriptor( name );
+
+ if ( !descriptor )
+ {
+ // event unknown to client, skip data
+ while ( msg->m_DataIn.ReadUBitLong( 3 ) )
+ msg->m_DataIn.ReadString( name, sizeof(name) );
+
+ continue;
+ }
+
+ // remove old definition list
+ if ( descriptor->keys )
+ descriptor->keys->deleteThis();
+
+ descriptor->keys = new KeyValues("descriptor");
+
+ int datatype = msg->m_DataIn.ReadUBitLong( 3 );
+
+ while ( datatype != TYPE_LOCAL )
+ {
+ msg->m_DataIn.ReadString( name, sizeof(name) );
+ descriptor->keys->SetInt( name, datatype );
+
+ datatype = msg->m_DataIn.ReadUBitLong( 3 );
+ }
+
+ descriptor->eventid = id;
+ }
+
+ // force client to answer what events he listens to
+ m_bClientListenersChanged = true;
+
+ return true;
+}
+
+void CGameEventManager::WriteListenEventList(CLC_ListenEvents *msg)
+{
+ msg->m_EventArray.ClearAll();
+
+ // and know tell the server what events we want to listen to
+ for (int i=0; i < m_GameEvents.Count(); i++ )
+ {
+ CGameEventDescriptor &descriptor = m_GameEvents[i];
+
+ bool bHasClientListener = false;
+
+ for ( int j=0; j<descriptor.listeners.Count(); j++ )
+ {
+ CGameEventCallback *listener = descriptor.listeners[j];
+
+ if ( listener->m_nListenerType == CGameEventManager::CLIENTSIDE ||
+ listener->m_nListenerType == CGameEventManager::CLIENTSIDE_OLD )
+ {
+ // if we have a client side listener and server knows this event, add it
+ bHasClientListener = true;
+ break;
+ }
+ }
+
+ if ( !bHasClientListener )
+ continue;
+
+ if ( descriptor.eventid == -1 )
+ {
+ DevMsg("Warning! Client listens to event '%s' unknown by server.\n", descriptor.name );
+ continue;
+ }
+
+ msg->m_EventArray.Set( descriptor.eventid );
+ }
+}
+
+IGameEvent *CGameEventManager::CreateEvent( CGameEventDescriptor *descriptor )
+{
+ return new CGameEvent ( descriptor );
+}
+
+IGameEvent *CGameEventManager::CreateEvent( const char *name, bool bForce )
+{
+ if ( !name || !name[0] )
+ return NULL;
+
+ CGameEventDescriptor *descriptor = GetEventDescriptor( name );
+
+ // check if this event name is known
+ if ( !descriptor )
+ {
+ DevMsg( "CreateEvent: event '%s' not registered.\n", name );
+ return NULL;
+ }
+
+ // event is known but no one listen to it
+ if ( descriptor->listeners.Count() == 0 && !bForce )
+ {
+ return NULL;
+ }
+
+ // create & return the new event
+ return new CGameEvent ( descriptor );
+}
+
+bool CGameEventManager::FireEvent( IGameEvent *event, bool bServerOnly )
+{
+ return FireEventIntern( event, bServerOnly, false );
+}
+
+bool CGameEventManager::FireEventClientSide( IGameEvent *event )
+{
+ return FireEventIntern( event, false, true );
+}
+
+IGameEvent *CGameEventManager::DuplicateEvent( IGameEvent *event )
+{
+ CGameEvent *gameEvent = dynamic_cast<CGameEvent*>(event);
+
+ if ( !gameEvent )
+ return NULL;
+
+ // create new instance
+ CGameEvent *newEvent = new CGameEvent ( gameEvent->m_pDescriptor );
+
+ // free keys
+ newEvent->m_pDataKeys->deleteThis();
+
+ // and make copy
+ newEvent->m_pDataKeys = gameEvent->m_pDataKeys->MakeCopy();
+
+ return newEvent;
+}
+
+void CGameEventManager::ConPrintEvent( IGameEvent *event)
+{
+ CGameEventDescriptor *descriptor = GetEventDescriptor( event );
+
+ if ( !descriptor )
+ return;
+
+ KeyValues *key = descriptor->keys->GetFirstSubKey();
+
+ while ( key )
+ {
+ const char * keyName = key->GetName();
+
+ int type = key->GetInt();
+
+ switch ( type )
+ {
+ case TYPE_LOCAL : ConMsg( "- \"%s\" = \"%s\" (local)\n", keyName, event->GetString(keyName) ); break;
+ case TYPE_STRING : ConMsg( "- \"%s\" = \"%s\"\n", keyName, event->GetString(keyName) ); break;
+ case TYPE_FLOAT : ConMsg( "- \"%s\" = \"%.2f\"\n", keyName, event->GetFloat(keyName) ); break;
+ default: ConMsg( "- \"%s\" = \"%i\"\n", keyName, event->GetInt(keyName) ); break;
+ }
+ key = key->GetNextKey();
+ }
+}
+
+bool CGameEventManager::FireEventIntern( IGameEvent *event, bool bServerOnly, bool bClientOnly )
+{
+ if ( event == NULL )
+ return false;
+
+ Assert( !(bServerOnly && bClientOnly) ); // it can't be both
+
+ VPROF_("CGameEventManager::FireEvent", 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false,
+ bClientOnly ? BUDGETFLAG_CLIENT : ( bServerOnly ? BUDGETFLAG_SERVER : BUDGETFLAG_OTHER ) );
+
+ CGameEventDescriptor *descriptor = GetEventDescriptor( event );
+
+ if ( descriptor == NULL )
+ {
+ DevMsg( "FireEvent: event '%s' not registered.\n", event->GetName() );
+ FreeEvent( event );
+ return false;
+ }
+
+ tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s (name: %s listeners: %d)", __FUNCTION__, tmDynamicString( TELEMETRY_LEVEL0, event->GetName() ), descriptor->listeners.Count() );
+
+ // show game events in console
+ if ( net_showevents.GetInt() > 0 )
+ {
+ if ( bClientOnly )
+ {
+ ConMsg( "Game event \"%s\", Tick %i:\n", descriptor->name, cl.GetClientTickCount() );
+ ConPrintEvent( event );
+ }
+ else if ( net_showevents.GetInt() > 1 )
+ {
+ ConMsg( "Server event \"%s\", Tick %i:\n", descriptor->name, sv.GetTick() );
+ ConPrintEvent( event );
+ }
+ }
+
+ for ( int i = 0; i < descriptor->listeners.Count(); i++ )
+ {
+ CGameEventCallback *listener = descriptor->listeners.Element( i );
+
+ Assert ( listener );
+
+ // don't trigger server listners for clientside only events
+ if ( ( listener->m_nListenerType == SERVERSIDE ||
+ listener->m_nListenerType == SERVERSIDE_OLD ) &&
+ bClientOnly )
+ continue;
+
+ // don't trigger clientside events, if not explicit a clientside event
+ if ( ( listener->m_nListenerType == CLIENTSIDE ||
+ listener->m_nListenerType == CLIENTSIDE_OLD ) &&
+ !bClientOnly )
+ continue;
+
+ // don't broadcast events if server side only
+ if ( listener->m_nListenerType == CLIENTSTUB && (bServerOnly || bClientOnly) )
+ continue;
+
+ // TODO optimized the serialize event for clients, call only once and not per client
+
+ // fire event in this listener module
+ if ( listener->m_nListenerType == CLIENTSIDE_OLD ||
+ listener->m_nListenerType == SERVERSIDE_OLD )
+ {
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "FireGameEvent (i: %d, listenertype: %d (old))", i, listener->m_nListenerType );
+
+ // legacy support for old system
+ IGameEventListener *pCallback = static_cast<IGameEventListener*>(listener->m_pCallback);
+ CGameEvent *pEvent = static_cast<CGameEvent*>(event);
+
+ pCallback->FireGameEvent( pEvent->m_pDataKeys );
+ }
+ else
+ {
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "FireGameEvent (i: %d, listenertype: %d (new))", i, listener->m_nListenerType );
+
+ // new system
+ IGameEventListener2 *pCallback = static_cast<IGameEventListener2*>(listener->m_pCallback);
+
+ pCallback->FireGameEvent( event );
+ }
+ }
+
+ // free event resources
+ FreeEvent( event );
+
+ return true;
+}
+
+bool CGameEventManager::SerializeEvent( IGameEvent *event, bf_write* buf )
+{
+ CGameEventDescriptor *descriptor = GetEventDescriptor( event );
+
+ Assert( descriptor );
+
+ buf->WriteUBitLong( descriptor->eventid, MAX_EVENT_BITS );
+
+ // now iterate trough all fields described in gameevents.res and put them in the buffer
+
+ KeyValues * key = descriptor->keys->GetFirstSubKey();
+
+ if ( net_showevents.GetInt() > 2 )
+ {
+ DevMsg("Serializing event '%s' (%i):\n", descriptor->name, descriptor->eventid );
+ }
+
+ while ( key )
+ {
+ const char * keyName = key->GetName();
+
+ int type = key->GetInt();
+
+ if ( net_showevents.GetInt() > 2 )
+ {
+ DevMsg(" - %s (%i)\n", keyName, type );
+ }
+
+ //Make sure every key is used in the event
+ // Assert( event->FindKey(keyName) && "GameEvent field not found in passed KeyValues" );
+
+ // see s_GameEnventTypeMap for index
+ switch ( type )
+ {
+ case TYPE_LOCAL : break; // don't network this guy
+ case TYPE_STRING: buf->WriteString( event->GetString( keyName, "") ); break;
+ case TYPE_FLOAT : buf->WriteFloat( event->GetFloat( keyName, 0.0f) ); break;
+ case TYPE_LONG : buf->WriteLong( event->GetInt( keyName, 0) ); break;
+ case TYPE_SHORT : buf->WriteShort( event->GetInt( keyName, 0) ); break;
+ case TYPE_BYTE : buf->WriteByte( event->GetInt( keyName, 0) ); break;
+ case TYPE_BOOL : buf->WriteOneBit( event->GetInt( keyName, 0) ); break;
+ default: DevMsg(1, "CGameEventManager: unkown type %i for key '%s'.\n", type, key->GetName() ); break;
+ }
+
+ key = key->GetNextKey();
+ }
+
+ return !buf->IsOverflowed();
+}
+
+IGameEvent *CGameEventManager::UnserializeEvent( bf_read *buf)
+{
+ char databuf[MAX_EVENT_BYTES];
+
+ // read event id
+
+ int eventid = buf->ReadUBitLong( MAX_EVENT_BITS );
+
+ // get event description
+ CGameEventDescriptor *descriptor = GetEventDescriptor( eventid );
+
+ if ( descriptor == NULL )
+ {
+ DevMsg( "CGameEventManager::UnserializeEvent:: unknown event id %i.\n", eventid );
+ return NULL;
+ }
+
+ // create new event
+ IGameEvent *event = CreateEvent( descriptor );
+
+ if ( !event )
+ {
+ DevMsg( "CGameEventManager::UnserializeEvent:: failed to create event %s.\n", descriptor->name );
+ return NULL;
+ }
+
+ KeyValues * key = descriptor->keys->GetFirstSubKey();
+
+ while ( key )
+ {
+ const char * keyName = key->GetName();
+
+ int type = key->GetInt();
+
+ switch ( type )
+ {
+ case TYPE_LOCAL : break; // ignore
+ case TYPE_STRING : if ( buf->ReadString( databuf, sizeof(databuf) ) )
+ event->SetString( keyName, databuf );
+ break;
+ case TYPE_FLOAT : event->SetFloat( keyName, buf->ReadFloat() ); break;
+ case TYPE_LONG : event->SetInt( keyName, buf->ReadLong() ); break;
+ case TYPE_SHORT : event->SetInt( keyName, buf->ReadShort() ); break;
+ case TYPE_BYTE : event->SetInt( keyName, buf->ReadByte() ); break;
+ case TYPE_BOOL : event->SetInt( keyName, buf->ReadOneBit() ); break;
+ default: DevMsg(1, "CGameEventManager: unknown type %i for key '%s'.\n", type, key->GetName() ); break;
+ }
+
+ key = key->GetNextKey();
+ }
+
+ return event;
+}
+
+// returns true if this listener is listens to given event
+bool CGameEventManager::FindListener( IGameEventListener2 *listener, const char *name )
+{
+ CGameEventDescriptor *pDescriptor = GetEventDescriptor( name );
+
+ if ( !pDescriptor )
+ return false; // event is unknown
+
+ CGameEventCallback *pCallback = FindEventListener( listener );
+
+ if ( !pCallback )
+ return false; // listener is unknown
+
+ // see if listener is in the list for this event
+ return pDescriptor->listeners.IsValidIndex( pDescriptor->listeners.Find( pCallback ) );
+}
+
+CGameEventCallback* CGameEventManager::FindEventListener( void* pCallback )
+{
+ for (int i=0; i < m_Listeners.Count(); i++ )
+ {
+ CGameEventCallback *listener = m_Listeners.Element(i);
+
+ if ( listener->m_pCallback == pCallback )
+ {
+ return listener;
+ }
+ }
+
+ return NULL;
+}
+
+void CGameEventManager::RemoveListener(IGameEventListener2 *listener)
+{
+ CGameEventCallback *pCallback = FindEventListener( listener );
+
+ if ( pCallback == NULL )
+ {
+ return;
+ }
+
+ // remove reference from events
+ for (int i=0; i < m_GameEvents.Count(); i++ )
+ {
+ CGameEventDescriptor &et = m_GameEvents.Element( i );
+ et.listeners.FindAndRemove( pCallback );
+ }
+
+ // and from global list
+ m_Listeners.FindAndRemove( pCallback );
+
+ if ( pCallback->m_nListenerType == CLIENTSIDE )
+ {
+ m_bClientListenersChanged = true;
+ }
+
+ delete pCallback;
+}
+
+int CGameEventManager::LoadEventsFromFile( const char * filename )
+{
+ if ( UTL_INVAL_SYMBOL == m_EventFiles.Find( filename ) )
+ {
+ CUtlSymbol id = m_EventFiles.AddString( filename );
+ m_EventFileNames.AddToTail( id );
+ }
+
+ KeyValues * key = new KeyValues(filename);
+ KeyValues::AutoDelete autodelete_key( key );
+
+ if ( !key->LoadFromFile( g_pFileSystem, filename, "GAME" ) )
+ return false;
+
+ int count = 0; // number new events
+
+ KeyValues * subkey = key->GetFirstSubKey();
+
+ while ( subkey )
+ {
+ if ( subkey->GetDataType() == KeyValues::TYPE_NONE )
+ {
+ RegisterEvent( subkey );
+ count++;
+ }
+
+ subkey = subkey->GetNextKey();
+ }
+
+ if ( net_showevents.GetBool() )
+ DevMsg( "Event System loaded %i events from file %s.\n", m_GameEvents.Count(), filename );
+
+ return m_GameEvents.Count();
+}
+
+void CGameEventManager::ReloadEventDefinitions()
+{
+ for ( int i=0; i< m_EventFileNames.Count(); i++ )
+ {
+ const char *filename = m_EventFiles.String( m_EventFileNames[i] );
+ LoadEventsFromFile( filename );
+ }
+
+ // we are the server, build string table now
+ int number = m_GameEvents.Count();
+
+ for (int j = 0; j<number; j++)
+ {
+ m_GameEvents[j].eventid = j;
+ }
+}
+
+bool CGameEventManager::AddListener( IGameEventListener2 *listener, const char *event, bool bServerSide )
+{
+ if ( !event )
+ return false;
+
+ // look for the event descriptor
+ CGameEventDescriptor *descriptor = GetEventDescriptor( event );
+
+ if ( !descriptor )
+ {
+ DevMsg( "CGameEventManager::AddListener: event '%s' unknown.\n", event );
+ return false; // that should not happen
+ }
+
+ return AddListener( listener, descriptor, bServerSide ? SERVERSIDE : CLIENTSIDE );
+}
+
+bool CGameEventManager::AddListener( void *listener, CGameEventDescriptor *descriptor, int nListenerType )
+{
+ if ( !listener || !descriptor )
+ return false; // bahh
+
+ // check if we already know this listener
+ CGameEventCallback *pCallback = FindEventListener( listener );
+
+ if ( pCallback == NULL )
+ {
+ // add new callback
+ pCallback = new CGameEventCallback;
+ m_Listeners.AddToTail( pCallback );
+
+ pCallback->m_nListenerType = nListenerType;
+ pCallback->m_pCallback = listener;
+ }
+ else
+ {
+ // make sure that it hasn't changed:
+ Assert( pCallback->m_nListenerType == nListenerType );
+ Assert( pCallback->m_pCallback == listener );
+ }
+
+ // add to event listeners list if not already in there
+ if ( descriptor->listeners.Find( pCallback ) == descriptor->listeners.InvalidIndex() )
+ {
+ descriptor->listeners.AddToTail( pCallback );
+
+ if ( nListenerType == CLIENTSIDE || nListenerType == CLIENTSIDE_OLD )
+ m_bClientListenersChanged = true;
+ }
+
+ return true;
+}
+
+
+bool CGameEventManager::RegisterEvent( KeyValues * event)
+{
+ if ( event == NULL )
+ return false;
+
+ if ( m_GameEvents.Count() == MAX_EVENT_NUMBER )
+ {
+ DevMsg( "CGameEventManager: couldn't register event '%s', limit reached (%i).\n",
+ event->GetName(), MAX_EVENT_NUMBER );
+ return false;
+ }
+
+ CGameEventDescriptor *descriptor = GetEventDescriptor( event->GetName() );
+
+ if ( !descriptor )
+ {
+ // event not known yet, create new one
+ int index = m_GameEvents.AddToTail();
+ descriptor = &m_GameEvents.Element(index);
+
+ AssertMsg2( V_strlen( event->GetName() ) <= MAX_EVENT_NAME_LENGTH, "Event named '%s' exceeds maximum name length %d", event->GetName(), MAX_EVENT_NAME_LENGTH );
+
+ Q_strncpy( descriptor->name, event->GetName(), MAX_EVENT_NAME_LENGTH );
+ }
+ else
+ {
+ // descriptor already know, but delete old definitions
+ descriptor->keys->deleteThis();
+ }
+
+ // create new descriptor keys
+ descriptor->keys = new KeyValues("descriptor");
+
+ KeyValues *subkey = event->GetFirstSubKey();
+
+ // interate through subkeys
+
+ while ( subkey )
+ {
+ const char *keyName = subkey->GetName();
+
+ // ok, check it's data type
+ const char * type = subkey->GetString();
+
+ if ( !Q_strcmp( "local", keyName) )
+ {
+ descriptor->local = Q_atoi( type ) != 0;
+ }
+ else if ( !Q_strcmp( "reliable", keyName) )
+ {
+ descriptor->reliable = Q_atoi( type ) != 0;
+ }
+ else
+ {
+ int i;
+
+ for (i = TYPE_LOCAL; i <= TYPE_BOOL; i++ )
+ {
+ if ( !Q_strcmp( type, s_GameEnventTypeMap[i]) )
+ {
+ // set data type
+ descriptor->keys->SetInt( keyName, i ); // set data type
+ break;
+ }
+ }
+
+ if ( i > TYPE_BOOL )
+ {
+ descriptor->keys->SetInt( keyName, 0 ); // unknown
+ DevMsg( "CGameEventManager:: unknown type '%s' for key '%s'.\n", type, subkey->GetName() );
+ }
+ }
+
+ subkey = subkey->GetNextKey();
+ }
+
+ return true;
+}
+
+CGameEventDescriptor *CGameEventManager::GetEventDescriptor(IGameEvent *event)
+{
+ CGameEvent *gameevent = dynamic_cast<CGameEvent*>(event);
+
+ if ( !gameevent )
+ return NULL;
+
+ return gameevent->m_pDescriptor;
+}
+
+CGameEventDescriptor *CGameEventManager::GetEventDescriptor(int eventid) // returns event name or NULL
+{
+ if ( eventid < 0 )
+ return NULL;
+
+ for ( int i = 0; i < m_GameEvents.Count(); i++ )
+ {
+ CGameEventDescriptor *descriptor = &m_GameEvents[i];
+
+ if ( descriptor->eventid == eventid )
+ return descriptor;
+ }
+
+ return NULL;
+}
+
+void CGameEventManager::FreeEvent( IGameEvent *event )
+{
+ if ( !event )
+ return;
+
+ delete event;
+}
+
+CGameEventDescriptor *CGameEventManager::GetEventDescriptor(const char * name)
+{
+ if ( !name || !name[0] )
+ return NULL;
+
+ for (int i=0; i < m_GameEvents.Count(); i++ )
+ {
+ CGameEventDescriptor *descriptor = &m_GameEvents[i];
+
+ if ( Q_strcmp( descriptor->name, name ) == 0 )
+ return descriptor;
+ }
+
+ return NULL;
+}
+
+bool CGameEventManager::AddListenerAll( void *listener, int nListenerType )
+{
+ if ( !listener )
+ return false;
+
+ for (int i=0; i < m_GameEvents.Count(); i++ )
+ {
+ CGameEventDescriptor *descriptor = &m_GameEvents[i];
+
+ AddListener( listener, descriptor, nListenerType );
+ }
+
+ DevMsg("Warning! Game event listener registerd for all events. Use newer game event interface.\n");
+
+ return true;
+}
+
+void CGameEventManager::RemoveListenerOld( void *listener)
+{
+ CGameEventCallback *pCallback = FindEventListener( listener );
+
+ if ( pCallback == NULL )
+ {
+ DevMsg("RemoveListenerOld: couldn't find listener\n");
+ return;
+ }
+
+ // remove reference from events
+ for (int i=0; i < m_GameEvents.Count(); i++ )
+ {
+ CGameEventDescriptor &et = m_GameEvents.Element( i );
+ et.listeners.FindAndRemove( pCallback );
+ }
+
+ // and from global list
+ m_Listeners.FindAndRemove( pCallback );
+
+ if ( pCallback->m_nListenerType == CLIENTSIDE_OLD )
+ {
+ m_bClientListenersChanged = true;
+ }
+
+ delete pCallback;
+}