Implementing a generic Messaging System for Crimild

Since I’ve been busy working on some stuff other than Crimild, there has been little progress during the last week. Still, I’m going to take this opportunity to talk about one the latest features that was added to the engine: The Message Queue.

Introduction
Message Queues are used to send messages throughout a system, decoupling the sender from the receiving. For example, a player sends a message whenever he’s hit by an enemy regardless of whether a text will be displayed on the screen or a sound will be played as a result of that. On the other hand, new enemies may be spawned in the level once the player has opened a magical chest.

While I was working on the Dungeon demo I needed some sort of messaging system to communicate between the different objects that were part of the simulation. Since I couldn’t find any implementation that satisfies me, I ended up designing my own one.

I’m going to start by talking about a common approach that can be found in many textbooks, its benefits and drawbacks, and how I managed to fix the latest ones by designing a Message Queue implementation on top of C++ templates.

The Basic Approach
A common approach implements a Message Queue that is capable of storing references to message handlers, each of them handling a specific message type. When a new message arrives, the Queue forwards it to each of the corresponding handlers. Then, both the sender (the object that triggers the message) and the receivers (the message handlers) are totally decoupled.

Usually, a messaging system is implemented as shown in the following diagram:

Class diagram for a classical message queue implementation

The abstract base class Message provides a single pure virtual method used to obtain the actual message type. This method is used by both the MessageQueue and the MessageHandler classes to determine the type of the message during run-time. Both SpawnEnemyMessage and GameOverMessage implements getMessageType() as follows:

const char *SpawnEnemyMessage::getMessageType( void )
{
   return "Spawn Enemy";
}

const char *GameOverMessage::getMessageType( void )
{
   return "Game Over";
}

Besides the getMessageType() method, messages may contain additional information, like the player position, two objects colliding or a string to be displayed on the screen.

MessageHandler, another abstract base class, defines an interface for all handlers. MessageHandler objects are registered in the MessageQueue to listen for a specific message. When this happens, the handleMessage() method is called. Handlers are implemented as follows:

class GameOverMessageHandler : public MessageHandler {
public:
   virtual void handleMessage( Message *message )
   {
      GameOverMessageHandler *gameOverMessage = ( GameOverMessageHandler * ) message;
      // do something with the message here
   }
};

A MessageQueue object dispatches new messages to all of the registered handlers based on the message type. Handlers are stored in some sort of map using the message type as key. Dispatching messages is as simple as traversing the list of handlers corresponding to the message type:

//...
// throw a message
messageQueue.pushMessage( new PlayerIsDeadMessage() );
//...

void MessageQueue::dispatchMessage( Message *message )
{
   for ( std::list::iterator it = _handlers[ message->getMessageType() ].begin();
         it != _handlers[ message->getMessageType() ].end();
         it++ ) {
      it->handleMessage( message );
   }
}

Known Issues
The above implementation is pretty basic, but it serves to illustrate a common approach for a message queue implementation that can be seen in many textbooks. This approach has several issues:

Message Identifiers
One of things that annoyed me the most when working with other message queue implementations is the requirement of declaring a message type for each  Message-derived class. Since I already have to code a new class for each message, using a message identifier seems a bit redundant.

Handling Multiple Messages in the same class
Take a look back at the handleMessage() method declaration in the MessageHandler class.

virtual void handleMessage( Message *message )

Handlers are implemented by sub-classing MessageHandler and implementing the handleMessage() method. The signature for that method is indicating that the argument is of type Message, meaning that all messages will be handled by the same function. But what if we want to handle multiple messages in the same MessageHandler-derived class? Since we can’t use function overloading, the only way left is to ask for the message type within the function using an if statement:

class MultipleMessageHandler : public MessageHandler {
public:
   void handleMessage( Message *message )
   {
      if ( message->getMessageType() == "Game Over" ) {
         // do something
      }
      else if (message->getMessageType() == "Spawn Enemy" ) {
         // do something
      }
   }
};

Explicit casting
In the code examples above, you may have noticed that we’re explicitly casting the message to its actual type before using it. Like I mentioned before, the message may contain additional information that it’s required in order to handle it properly and the only way to get that is to use explicit casting. Although this may seem harmless, keep in mind that if we have several handlers for the same message, we need use casting in each of them.

Requirements
So, in order for my implementation to be successful, it must meet the following requirements:
1. Dispatch messages to handlers in a simple way. I need a simple interface that provides me a single entry point for pushing new messages and dispatching them to their correspondent handlers.
2. Support any number of messages.
3. No need for message identifiers. I want the message queue to use the message class itself to recognize the type and dispatch the messages to the appropriated handlers.
4. No need for explicit casting on handlers.
5. Allow any number of handlers for any given message.
6. Allow a single class to be the handler for any number of messages.

A solution: A Multi-Queue System
Let’s step back for a second and assume that our system is only capable of handling only a single kind of messages during its execution. If so, there wouldn’t be a need for neither a message identifier nor explicit casting because everyone will know what are we talking about. Let’s suppose we have a MessageDispatcher class that works only with that specific message type. This dispatcher will then delegate message handling into one or more MessageHandler objects. Once again, there is no need to use explicit casting within the handlers since there is only one message in our system. A class diagram for such a system will be something like this:

A MessageDispatcher that handles only one message type

That works great in theory, but real applications have a lot of different messages. How do we change this design to support multiple message types? All we need to do is to implement a new MessageDispatcher and a new MessageHandler class per message in our system:

A MessageDispatcher that handles another message type

I know what you’re thinking. Having to implement a dispatcher and a handler class per message type is overkill. A lot of classes needs to be written ending up with thousands of lines of code to maintain. It’s total madness!!!

Of course, I wouldn’t be writing this if I didn’t know that already. Go on and take a look at the diagram above again. Have you noticed that all the methods are pretty much the same, except for the the type of the argument that represents the message itself? That has to mean something, right? If you haven’t figured it out yet, let me give you a hint: C++ has that beautiful feature call Templates. Templates are used to implement an algorithm independently of the argument types. Then, we will use templates to avoid having to write new classes for both dispatch and handling messages.

class MessageDispatcher {
public:
   virtual void dispatchMessages( void ) = 0;
   virtual void discardAllMessages( void ) = 0;
   virtual void reset( void ) = 0;
};

template < class T >
class MessageDispatcherImpl : public MessageDispatcher {
public:
   static MessageDispatcherImpl &getInstance( void );

public:
   virtual void dispatchMessages( void );

   void pushMessage( T *message );

   void registerHandler( MessageHandler< T > *handler );

   void unregisterHandler( MessageHandler< T > *handler );
};

The abstract base class MessageDispatcher defines the interface for all dispatchers that are implemented using the template class MessageDispatcherImpl. We need an abstract class because we’re going to register all dispatchers into a list within a MessageQueue object (remember that templates end up creating new classes that are unrelated).

So far, we have a template class that let us work with an infinite number of messages. The next step is to define an interface that will let us handle all of the dispatchers in a simple way. That’s where the MessageQueue class comes into play:

class MessageQueue {
public:
   void registerDispatcher( MessageDispatcher *dispatcher );

public:
   void dispatchMessages( void );

   template
   void pushMessage( T *message );
};

The MessageQueue class is just a storage for message dispatchers. The registerDispatcher() method is called by the MessageDispatcherImpl constructor automatically.

The template method pushMessage is implemented as follows:

template< class T >
void MessageQueue::pushMessage( T *message )
{
   MessageDispatcherImpl::getInstance().pushMessage( message );
}

This method ensure that the message is store in the proper dispatcher.

Using the MessageQueue
Using this messaging system is pretty easy (since that was the point the whole time, right?). Suppose we have a message called SpawnEnemyMessage:

class SpawnEnemyMessage : public Message {
public:
	Vector3f position;
};

Our game class is going to register itself as a handler for such message:

class Game : public MessageHandler< SpawnEnemyMessage > {
public:
   // ...
   void handleMessage( SpawnEnemyMessage *message )
   {
       // do something with the message here
   }
};
MessageQueue::getInstance().push( new SpawnEnemyMessage() );

Notice that there is no need for either a hardcoded message type nor for explicit casts, making the code easier to read and maintain.

About the test project
I uploaded a simple test project that makes use of the MessageQueue class, so you can take a look at it in action. It has no dependencies with Crimild and comes with its own CMake configuration, so it’s really easy to use. You can find it in the Files page on SourceForge:

https://sourceforge.net/projects/crimild/files/
Please keep in mind that this is an example application of an unstable feature. There are some bugs that have to be fixed before releasing it to the public.

Future Work
There are a couple of things that need some more work. For example, when is the right time to dispatch all queued messages? The MessageQueue class supports both immediate and delayed modes for message dispatching, but for the last one I’m trying to understand if dispatching messages at the very beginning of the update pass is the best solution.
On the other hand, the networking library (which I’m redesigning from scratch) will require message identifiers in order to stream messages thorugh the network. I strongly believe that I won’t have any issue in adding some typed messages here and there, but only time will tell.
And of course, there are a couple of bugs to fixed.

References
If you want to know more about C++ templates and generic design, let me point you to Andrei Alexandrescu’s book “Modern C++ Design: Generic Programming and Design Patterns Applied”. It’s a great book and I recommend it not only to C++ programmers but to anyone that has the need of designing a generic API.

That’s it for this week. I hope you find this useful and you can always contact me if you have any questions or comments.