Unity Notification System

Posted on Posted in Code, Development

EDIT – WARNING
This article is now defunct, the guts of the Notification system has since been rewritten to optimize it when large numbers of GameObjects are being observed in game. A new article will be written soon to outline the changes. In the mean time you can find the required source files for it here:

Notification.cs
INotificationDispatcher.cs

 

To start off I’m going to share a link to a scaled down version of the Spacepuppy Unity Framework. under the MIT license at google-code. Here you’ll find code related to what I’ve discussed up to this point as well as a few other minor things that go along with them to make life a little easier in unity. I plan to talk about various aspects of what’s in there over the coming weeks.

Spacepuppy Unity Notification System

The next part I want to discuss today is the Notification System that I designed to be used with the Entity pattern we discussed in the last article. One major issue I had after we would create our mobs was that if we had some hitbox for instance inside the skeleton somewhere, there was no easy way to listen for some message being sent by it. I could call ‘SendMessage’ on the root, but I never really liked the unity messaging system as a whole. It’s lack of type safety, and use of magic strings, didn’t really jive with me.

Another option is Mono/.Net events. The nice thing about these is that they are statically typed; ensuring that the dispatcher and listener will couple together correctly. The problem though is that a reference to the specific component dispatching the event is required. This means that we have to dig out a reference from the entity hierarchy, and attach the listener to the dispatcher directly.

What I want is a statically typed messaging system that allows coupling to an entity, as opposed to the constituent part, and listen for events.

Now I know that a .Net/Mono event is really just a delegate. Delegates are really just a special type that creates an object out of a method. More pure object oriented languages don’t have this feature, like Java for instance. And instead Java uses the observer pattern to accomplish events. Now in the observer pattern the ‘subject’ defines a method to accept an ‘observer’ object of a statically defined type. All observers must therefore implement this defined ‘observer’ type. This creates the strongly typed link between ‘subject’ and ‘observer’. The ‘subject’ though is a single object and not an entire entity like we have. Essentially we want a strongly typed observer, with a loosely typed subject.

So what couples the observer pattern to the subject is the method on the subject to register an observer.

We can decouple this from the subject by instead creating a generalized method that we pass both the subject and observer to when creating the link. We’ll also need a method to signal the event formed by the link. It could be something like this:

But wait, that’s not generalized at all. It only works for observers of type ISomeEventObserver. How about we instead have an abstract observer type that all events inherit from. And then we can use generics to define which observer event type to register for and to post.

There we go, much better. But wait… I’m still sort of meh about this design. I still have to create an observer object for every event. This is a part of the observer pattern I don’t like that events take care of using delegates. Lets use a delegate then! How about we instead of defining an observer type, we define a Notification type. Then when we register an observer, we register a delegate that is a method that accepts that notification type.

I kind of like this. Now we could implement PostNotification to check the sender object for a root, and post to the root as well as to the object directly. We could even post globally as well that some notification occurred.

All right, so lets start putting this all together. First we start with that Notification class that all notification types should inherit from. This will be an abstract class that stores the most rudimentary information we need for a Notification. One thing I can think of is who the sender is. That sender is typed as an object, but 9 times out of 10 that sender will be a Component. And in that case, be related to a GameObject. So lets also just make a quick reference to that GameObject too.

We’ll also need to define the interface for registering and posting notifications. Personally I’m going to just make them static methods on this class here. If I want to listen for a notification, I register with the notification class. Arguments could be made for making the notification manager its own class and even make it an instanced class at that. But really, I don’t see a need for multiple notification managers and will just put it here.

Also I’m going to expand those methods we discussed before. When posting a notification I’m going to allow the sender to decide if notifying the root is really necessary or not. And I’m also going to include a parameter when registering a notification I’m going to allow the observer to decide if the reference can be weak or not. Weak references allow the weakly referenced object to be garbage collected even if the weak reference still exists. This can be useful if an observer gets destroyed, but isn’t removed from the observer pool for a subject.

We’ll of course also need a method to remove the observer. And a method to test if a sender has any observers could also be very helpful at times. For instance a subject may have to calculate a lot of data to include with the notification, such as collision information. But if there is no observers, why do all that work?

Lastly, lets also include methods to allow listening for a notification globally. Maybe you want an observer that listens for when ANY notification of ANY type occurs. I don’t necessarily need it all that much… but hey, it could be useful. So lets include it for hoorahs.

Now we have to implement these methods. First things first is that we will need to create a relationship between the sender and observer. A simple choice for this is the Dictionary class. With this we could make the key the observer, and the value the delegate chain of observers. Especially since delegates stack so nicely.

There’s a downside to this though. It doesn’t support weak references, and we also don’t have a way to store the global observers.

Lets first tackle the weak references issue. When we register we’re going to gather up two different types of observers. Strong and Weak observers. Now a weak reference is created by using the WeakReference Class (note – as of the writing of this article there is a generic WeakReference class as well, but it is a .Net 4.5 class and I do not believe it is available to the version of mono that unity uses). This is a predicament, our weak references will be typed a completely different object type from our delegates. Furthermore they don’t stack as nicely as delegates do. This says to me we’re going to have two collections, one being the strong delegates, the other being a List of WeakReference objects. Now I’ve had need for a list of WeakReferences in the past and have already written up a nice class to do most of the work for us. This way we can just use the list as a regular list and ignore the WeakReference aspect of it all together.

This class can be found here.

Another thing I realize is that a sender will be able to post several different notifications. We don’t want our ‘CollisionNotification’ triggering our ‘AttackNotification’. So we’re going to have to divy apart the notifications by type. This will again call for a dictionary… sorry, two dictionaries… pairing the notification type with the observers for that notification. The delegate dictionary is rather simple since delegates stack so nicely. It’s a basic as:

The weak references not so much. This is going to be a dictionary of lists. These too are a collection type that I’ve needed several times in the past, and I wanted to stream line the use of them as well. So I created a ListDictionary class as well that can be found here.

So now we have a dictionary pairing sender with a dictionary that pairs type with delegates. As well as a dictionary pairing sender with a dictionary of lists of weakreferences to delegates. On top of all that we will also need another two dictionaries for the global notification observers.

Arghhhhh. That’s a lot. Well… the classes I linked simplify this down a bit. But lets simplify it one step further and create a class that pulls the strong and weak references all under one roof and simplify the accessing of them. Lets call this a NotificationHandlerCollection. Implemented correctly we’re back to the original design of dictionary paring sender and delegate. We’ll now have a dictionary pairing sender and NotificationHandlerCollection. The collection can also just mirror the interface of the Notification observer factory to streamline it (basically the delegation pattern). As well as a method to clean out those weak references if they’ve gone dead.

Implementation is then fairly simple we just add or remove to either the strong or weak collection. As can be seen here:

Not only does this collection allow us to create a dictionary pairing a sender to its given collection. We can also have a separate collection just for the global observers as well. Then our static methods on the Notification factory just look up the appropriate collection and delegate to them properly.

In the case of the global observer it’s fairly simple as we just pass through the command:

The sender specific ones aren’t as simple as we want to allow for signaling the root as well. First off I made the dictionary pairing sender to NotificationHandlerCollection weak. This way if a sender dies, the collection doesn’t remain in the Notification factory. As with the other collections from before, I implemented a WeakKeyDictionary and it can be found here.

As for the related static methods, I’ll go through them 1 by 1.

RegisterObserver is fairly straight forward. We attempt to get the collection for this sender, if one doesn’t exist we create a collection. I also use this as a chance to clean the WeakKeyDictionary in case any senders have died since the last time an observer was registered.

Next in RemoveObserver we make sure the collection exists, and if so we remove the handler. If the collection is then empty, we also remove the collection. This way we don’t have inactive collections sitting around in memory. Again we also take this as a change to clean the WeakKeyDictionary.

PostNotification is where it gets more complicated. Here we have to attempt to get the collection for the sender and post a notification for that. But we then also need to check if the sender is a GameObject source, like a Component. If so we also dispatch a notification for the related GameObject, as well as for the root GameObject if the parameter says to. Lets also not forget to post to the global observer as well.

Finally, HasObserver should return true if the sender, the sender’s related GameObject, the sender’s root, or a global observer exists for the notification in question.

For the most part, we’re done. There’s just one last thing I want to do. Because we have all these weak references everywhere, I’ll want to make sure they cleaned up at some regular interval. So I set up a timer that does this for me. This utilizes a Timer system I wrote up that can be found here. I may go more into depth about them in a later article. In the mean time, if you don’t want to use it, these lines of code can just be removed from the completed class.

We’re now done with our Notification system. A full reference can be found here: https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyBase/Notification.cs.

We have one last thing to consider in regards to this though. How do we use it?

Well here’s my preferred method.

When I have a component that wants to post a notification I create a Notification directly in the component in question.

Then where I want to listen I register the observer OnEnable, and remove it OnDisable. I do it this way so that the observer doesn’t react if it’s not enabled. Remember that when I showed you the SPComponent before it already implemented OnEnable and OnDisable so these will be overrides, and that root is a member of SPComponent so I don’t need to find it.

[edit 4:06AM 8/15/2014]
A change to Notification.cs was added to the google code reference. PostNotification now returns a boolean for if an observer was found and received the Notification. As well as an attribute added to allow flagging a Notification type as requiring a receiver, else an exception occurs. This can be useful for debugging code, one can flag a notification as requiring a receiver, and if one isn’t found the console will throw up an exception stating as such.

Note, I personally use exception instead of Debug.LogWarning, because an exception can be caught in a try/catch and handled.

3 thoughts on “Unity Notification System

  1. Hi Dylan,
    awesome post and great code, thanks for doing this!
    I’ve run into some of the same problems within Unity that you describe in this blog series. Especially the issue of orchestrating sequences of event (via coroutines, notifications etc.) is something that I find rather difficult, and since how you’ve adressed them in a highly general manner, I’m now working my way through some of your code. 🙂
    One question though: NotificationHandlerCollection doesn’t seem to exist anymore in the current version of your framework, and NotificationPool doesn’t have a PostNotification() method, so I assume it’s not the replacement (havent quite figured out yet what it does). Can you point me to the main changes in SP since you wrote this post?
    Either way, thank’s a lot! /Wendelin

    1. Hey Wendelin,

      Yeah, I since rewrote the guts of the Notification system to make it more efficient. I no longer store the delegates globally (except for the explicit global notification listeners).

      I’ve been meaning to write a follow up article, but we’ve been neck deep in development. I plan to do so in the near future… your response definitely brought light to the fact I really should sooner rather than later.

      In the mean time I can direct you to the code that is required.

      Notification.cs – this is the base class all Notifications should inherit from and acts as a static interface for adding and removing them. The interface has not changed, only the implementation inside.
      https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyBase/Notification.cs

      INotificationDispatcher – This is the rest of the stuff necessary. For efficiency sake I put the burden of storing the listeners on the object that is being observed. This increased speeds of the Notification system when hundreds of GameObjects were on screen around 100 fold.
      https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyBase/INotificationDispatcher.cs

  2. Thanks for the tip, and glad to hear you are still planning more articles in your excellent series! I’ve spent all day yesterday going through your Notification* and RadicalCorouine* code, and I think I more or less get the principles now. Will start experimenting today, but it’s already clear to me that the architectural problems you’re trying to solve are exactly the one myself and many other Unity devs share. Thanks again!

Leave a Reply

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