Messaging systems for games (and an XNA implementation)

I have been coding and using various incarnations of the messaging system that I will describe below for some time now and I’m still not sure what to call it, it is not exactly an event-driven system or a message bus, message manager seems to be to closest description I can think of.

Now, the advantages of a message driven system should be fairly obvious (systems decoupling mostly) and not the subject of this post, what I have are few empirical rules for when to use messages versus direct systems collaboration:

  • If it is a fire-and-forget situation when you do not need a reply send a message.
  • If it appears that you are implementing an interface just to bring polymorphism to what appears to be unrelated classes then messaging is probably a better alternative. For example some of your game characters (but not all of them) can follow a leader, so you can do something like an IHasLeader interface with leader property and have your character classes implement this interface or you could send a “SetLeader” message and whoever is interested will receive that message and update their leader reference.
  • If you find that some central class holds and maintains various list of objects just for the purpose of changing their state see if you can refactor the code to use messages (usually the Player and the Gameplay implementation have a tendency to do this).
  • If there’s any kind of state that needs to be maintained do not use message, it will get complex real quick, in other words if it seems that you need to exchange multiple messages between components do not do it. Also, there will surely be an unforeseen sequence of messages that will result into subtle and apparently “Heisenbergian” bugs.

Back to my message manager, this is the XNA version of it and I have greatly reduced its features and code base to a very simple and unsophisticated mechanism (this is probably a consequence of starting with the actual game code instead of building a framework first). A few more things about it:

  • Untyped message content, I’m using strings and objects (this can be seen both as a feature and lack of one…).
  • No registering with the message manager, objects query the manager directly for messages directed to them.
  • Double buffered, an event is visible in the next frame.
  • Very little code, about 80 lines.


EDIT: Reddit user geishastudios had some very legitimate questions and wanted me to explain why am I doing things this way, this is my reply:
I needed a mechanism to pull messages vs a push/callback/delegate system so a component can decide when and if is going to process a message. I also needed to be able to skip processing certain messages if other messages where sent. My initial code was using the classic observer pattern with delegates and I ended up with a lot of checks to see what messages were received and was called and what not.

Another reason (and this is probably the main one) is that messages need to be “double-buffered”, basically all messages need to show up at once in the next frame, not partially in the current one, that would cause an event handler to work with an incomplete state since there was still stuff that was going to happen (there will be more messages) after it finished running, or it could itself send messages for components that already should have gotten their messages and they will get called again and I had to account for that. Anyway, it was all getting quite complicated and apparently the way I handling events was the cause. Now, this may say something about my code and the way entities are handling their state but this is my approach and it works pretty well for me.

The switch block is probably not faster but I did not see a performance hit for using it, there may even be a small improvement in performance and memory usage for broadcast events when a large numbers of components need to be notified of something (not really sure I can back this affirmation, it may have also been caused by other changes in the code). Also the switch blocks did not get terribly big in my case, each component gets 4, maybe 5 message types.

Slightly better type checking could be achieved by replacing strings with enums but I was just having too many and also enums do not have inheritance – anyway I ended up using strings.

Hope all this makes some sense.

Here is some code to give a better picture of what I’m talking about:

//the message manager should be globally available
public MessageManager MessageManager { get; private set; }
...
MessageManager = new MessageManager();
...

protected override void Update(GameTime gameTime) {
MessageManager.Update();
...
}

...
//send a message
MessageManager.Send(new Message {
Type = "DoSomething",
Sender = this,
Destination = someGameObject,
Payload = someItem
});

...
//somewhere in someGameObject's code
List messages = new List();
//find messages for someGameObject
MessageManager.FindMessagesByDestination(this, messages);
foreach (var m in messages) {
switch (m.Type) {
case "DoSomething":
DoSomething(m.Payload);
break;
...

Here is the full code of the MessageManager class, very simple stuff as you can see. There are multiple FindMessagesBy* methods (I got a bit into framework writing mode) but I think I’m using only FindMessagesByDestination and FindMessagesBySender in my code. There’s also a FindFutureMessage that I had to add because of an unforeseen need to maintain state, some component needed to know the content of a message that was sent in the current frame instead of waiting its turn next frame, if this happens to you it is probably a good indication you should not be using messages in this situation.

public class MessageManager {
private List lastFrameMessages = new List();
private List currentFrameMessages = new List();

public void Send(Message message) {
currentFrameMessages.Add(message);
}

public void FindMessagesByDestination(object destination, List result) {
for (var i = 0; i < lastFrameMessages.Count; i++) {
var m = lastFrameMessages[i];
if (m.Destination != null && m.Destination.Equals(destination)) {
result.Add(m);
}
}
}

public void FindMessagesBySender(Object sender, List result) {
for (var i = 0; i < lastFrameMessages.Count; i++) {
var m = lastFrameMessages[i];
if (m.Sender.Equals(sender)) {
result.Add(m);
}
}
}

public void FindMessage(Predicate criteria, List result) {
for (int i = 0; i < lastFrameMessages.Count; i++) {
Message m = lastFrameMessages[i];
if (criteria.Invoke(m)) {
result.Add(m);
}
}
}

public void FindMessagesByType(string type, List result) {
for (var i = 0; i < lastFrameMessages.Count; i++) {
var m = lastFrameMessages[i];
if (m.Type.Equals(type)) {
result.Add(m);
}
}
}

public void FindMessagesByTypeAndDestination(string type, object destination, List result) {
FindMessage(type, destination, lastFrameMessages, result);
}

public void FindFutureMessagesByTypeAndDestination(string type, object destination, List result) {
FindMessage(type, destination, currentFrameMessages, result);
}

public void FindMessagesByTypeAndSender(string type, Item sender, List result) {
for (int i = 0; i < lastFrameMessages.Count; i++) {
var m = lastFrameMessages[i];
if (m.Type.Equals(type) && m.Sender.Equals(sender)) {
result.Add(m);
}
}
}

private static void FindMessage(string type, object destination, List frameMessages, List result) {
for (var i = 0; i < frameMessages.Count; i++) {
var m = frameMessages[i];
if (m.Destination != null && m.Type.Equals(type) && m.Destination.Equals(destination)) {
result.Add(m);
}
}
}

public void Update() {
var t = lastFrameMessages;
lastFrameMessages = currentFrameMessages;
currentFrameMessages = t;
currentFrameMessages.Clear();
}
}

public struct Message {
public string Type;
public object Sender;
public object Destination;
public object Payload;

public Message(string type, object sender, object destination, object payload) {
Type = type;
Sender = sender;
Destination = destination;
Payload = payload;
}
}

5 thoughts on “Messaging systems for games (and an XNA implementation)

  1. Twitch

    This is quite a handy looking system; quite a bit more than my own basic dispatcher, I may have to borrow some ideas here 🙂

    Have you considered using LINQ to simplify your methods though?

    For example, this method:
    public void FindMessagesBySender(Object sender, List result) { for (var i = 0; i < lastFrameMessages.Count; i++) {
    var m = lastFrameMessages[i];
    if (m.Sender.Equals(sender)) {
    result.Add(m);
    }}}

    could be translated into this:
    public void FindMessagesBySender(Object sender, List result)
    { result = lastFrameMessages.Where( item => item.Sender.Equals( sender ) ).ToList(); }

    Which reads a hell of alot better, and I’m fairly certain LINQ performs well – although admittedly I haven’t done a benchmark comparison.

    Reply
  2. Gabriel

    Borrow away 🙂

    LINQ is probably fast enough, at least on the PC and definitely easier to read but I don’t really know how a LINQ generated collection behaves GC wise (my C#/.NET experience is limited to XNA and I speak the language with a bit of foreign Java accent).
    I was trying to limit the GC since the .NET runtime on the Xbox360 can be pretty bad at it (as you can see I even avoid foreach constructs because of potential garbage). Passing that result list as an argument does look disgusting but creating and returning a new one every frame was too costly.

    Reply
  3. Twitch

    I did some research and, yeah, LINQ is alot slower than a for loop. Surprisingly, foreach is also considerably slower than for, so it looks like your intuition was correct there!
    Since it’s far too useful for it’s own good, I decided to implement my own version of LINQ’s extension methods. You might find ’em useful, check it out:

    public static List Where( this List list, Func predicate )
    {
    var results = new List();
    int count = list.Count;

    for( int i=0; i{
    var item = list[i];
    if( predicate.Invoke( item ) )
    results.Add( item );
    }

    return results;
    }

    If defined in a public class somewhere (I use a class named Extensions solely for this purpose), this adds the Where() method to all Lists. I’ve done the same for things like ForEach, First, and Any but I’m sure you could figure those out.
    Much faster than regular LINQ for these purposes, and with the same concise syntax 😀

    Reply
  4. Twitch

    that would be public static List[T] Where[T]( this List[T] list, Func[T, bool] predicate ), were it not for the HTML filter stripping out my angular brackets.

    Reply
  5. Chetan Prasad

    Hi,
    Looking at your messaging system, i find it to be handy in the game i am working on , i basically have an actor class which is the base class for all the actors in the game.

    Now i want to use the same actor class for player as well as for enemies.
    I thought, with your messaging system i could send messages to the actor to handle states instead of assigning key configurations to it and making it player specific.

    I basically want the actor class to be generic, so that it could be used by both player and AI.
    Am i going right?, Do you have any suggestion on how i should bring this to my use?

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *