Event manager priority chaining

listeners can register with a priority to get an event into an ordered stream of listeners
This commit is contained in:
marauder2k7 2026-02-19 10:06:54 +00:00
parent 562756a306
commit 299d358d0b
2 changed files with 63 additions and 42 deletions

View file

@ -79,26 +79,30 @@ bool EventManagerListener::onMessageReceived( StringTableEntry queue, const char
if( subscribers == NULL )
return true;
for (U32 i = 0; i < subscribers->size(); i++)
for (U32 i = 0; i < subscribers->size();)
{
Subscriber* itter = &((*subscribers)[i]);
if (itter->listener == NULL)
Subscriber& itter = (*subscribers)[i];
if (itter.listener == NULL)
{
(*subscribers).erase(i);
subscribers->erase(i);
continue;
}
else if (!itter->removeFlag)
if (!itter.removeFlag)
{
itter->callDepth++;
Con::executef(itter->listener, itter->callback, data);
itter->callDepth--;
if (itter->removeFlag && itter->callDepth == 0)
itter.callDepth++;
Con::executef(itter.listener, itter.callback, data);
itter.callDepth--;
if (itter.removeFlag && itter.callback == 0)
{
(*subscribers).erase(i);
subscribers->erase(i);
continue;
}
}
if (subscribers->size() == 0)
return true;
i++;
}
return true;
@ -270,7 +274,7 @@ bool EventManager::postEvent( const char* event, const char* data )
// CodeReview [tom, 2/20/2007] The "listener" argument was an IMessageListener,
// but it was actually used as a SimObject and never a listener. Thus, it is now a SimObject.
bool EventManager::subscribe(SimObject *callbackObj, const char* event, const char* callback /*= NULL */)
bool EventManager::subscribe(SimObject *callbackObj, const char* event, const char* callback /*= NULL */, S32 priority /*=0*/)
{
// Make sure the event is valid.
if( !isRegisteredEvent( event ) )
@ -300,6 +304,7 @@ bool EventManager::subscribe(SimObject *callbackObj, const char* event, const ch
subscriber.listener = callbackObj;
subscriber.event = StringTable->insert( event );
subscriber.callback = StringTable->insert( cb );
subscriber.priority = priority;
subscriber.callDepth = 0;
subscriber.removeFlag = false;
@ -311,8 +316,22 @@ bool EventManager::subscribe(SimObject *callbackObj, const char* event, const ch
// If the event exists, there should always be a valid subscriber list.
AssertFatal( subscribers, "Invalid event subscriber list." );
// Add the subscriber.
subscribers->push_back( subscriber );
// Add the subscriber at the appropriate index based on priority.
S32 insertIndex = subscribers->size();
for (S32 i = 0; i < subscribers->size(); i++)
{
EventManagerListener::Subscriber& cur = (*subscribers)[i];
if (subscriber.priority > cur.priority)
{
insertIndex = i;
break;
}
}
subscribers->insert(insertIndex);
(*subscribers)[insertIndex] = subscriber;
return true;
}
@ -342,10 +361,10 @@ void EventManager::remove(SimObject *cbObj, const char* event)
// Erase the event.
if( iter->listener == cbObj )
{
if (iter->callDepth > 0)
iter->removeFlag = true;
else
subscribers->erase_fast( iter );
if (iter->callDepth > 0)
iter->removeFlag = true;
else
subscribers->erase_fast( iter );
break;
}
}
@ -356,21 +375,21 @@ void EventManager::removeAll(SimObject *cbObj)
// Iterate over all events.
for( Vector<StringTableEntry>::const_iterator iter1 = mEvents.begin(); iter1 != mEvents.end(); iter1++ )
{
Vector<EventManagerListener::Subscriber>* subscribers = mListener.mSubscribers.retreive( *iter1 );
if( !subscribers )
continue;
for( Vector<EventManagerListener::Subscriber>::iterator iter2 = subscribers->begin(); iter2 != subscribers->end(); iter2++ )
{
// Erase the event.
if( iter2->listener == cbObj )
{
if (iter2->callDepth > 0)
iter2->removeFlag = true;
else
subscribers->erase_fast( iter2 );
break;
}
}
Vector<EventManagerListener::Subscriber>* subscribers = mListener.mSubscribers.retreive( *iter1 );
if( !subscribers )
continue;
for( Vector<EventManagerListener::Subscriber>::iterator iter2 = subscribers->begin(); iter2 != subscribers->end(); iter2++ )
{
// Erase the event.
if( iter2->listener == cbObj )
{
if (iter2->callDepth > 0)
iter2->removeFlag = true;
else
subscribers->erase_fast( iter2 );
break;
}
}
}
}
@ -460,7 +479,7 @@ DefineEngineMethod( EventManager, postEvent, bool, ( const char * evt, const cha
return object->postEvent( evt, data );
}
DefineEngineMethod( EventManager, subscribe, bool, ( const char * listenerName, const char * evt, const char * callback ), (""), "( SimObject listener, String event, String callback )\n\n"
DefineEngineMethod( EventManager, subscribe, bool, ( const char * listenerName, const char * evt, const char * callback, S32 priority ), ("", 0), "( SimObject listener, String event, String callback, int priority = 0 )\n\n"
"Subscribe a listener to an event.\n"
"@param listener The listener to subscribe.\n"
"@param event The event to subscribe to.\n"
@ -475,7 +494,7 @@ DefineEngineMethod( EventManager, subscribe, bool, ( const char * listenerName,
return false;
}
return object->subscribe( cbObj, evt, callback );
return object->subscribe( cbObj, evt, callback, priority);
}
DefineEngineMethod( EventManager, remove, void, ( const char * listenerName, const char * evt), , "( SimObject listener, String event )\n\n"

View file

@ -47,11 +47,13 @@ class EventManagerListener : public Dispatcher::IMessageListener
/// Stores subscription information for a subscriber.
struct Subscriber
{
SimObjectPtr< SimObject > listener; ///< The listener object.
StringTableEntry callback; ///< The callback to execute when the event is triggered.
StringTableEntry event; ///< The event being listened for.
U32 callDepth;
bool removeFlag;
SimObjectPtr< SimObject > listener; ///< The listener object.
StringTableEntry callback; ///< The callback to execute when the event is triggered.
StringTableEntry event; ///< The event being listened for.
S32 priority;
U32 callDepth;
bool removeFlag;
};
/// Subscriber table hashed by event name.
@ -154,7 +156,7 @@ public:
/// Triggers an event.
bool postEvent( const char* eventName, const char* data );
/// Adds a subscription to an event.
bool subscribe( SimObject *callbackObj, const char* event, const char* callback = NULL );
bool subscribe( SimObject *callbackObj, const char* event, const char* callback = NULL, S32 priority = 0 );
/// Remove a subscriber from an event.
void remove( SimObject *cbObj, const char* event );
void removeAll( SimObject *cbObj );