Callbacks and Messaging System (Event-driven programming)

I needed to add a smiley logic for the agents I have been developing at work. I planned smiley logic to manage itself, like a part of our brains. It was still going to be a part of AI, but the AI was not going to monitor and manage it closely as it does for the agent movement for example; an autonomous system in other words…

So, I designed an event-driven subsystem for the smiley logic. I added a SmileyManager to handle the events thrown by the game manager (someone scored, end of the game, beginning of the game, etc.), manage the time for the smileys by controlling SmileyScheduler, and forward the smiley requirements to the renderer via the game manager.

SmileyLogicDesign

But there was one important point that I had to consider: Having a realistic agent behaviour. And you know, if you want to have a realistic agent, you have to be careful what your agent does. Which means that you cannot have an agent that can send smileys under unrealistic conditions, such as while jumping or shooting, or it should not send one smiley another, and so on.

And actually this is the story how SmileyScheduler and SmileyTelegram (or messaging system in general) became a part of the story. In the end, SmileyScheduler became a layer between SmileyManager and SmileyLogic.

So, when the logic finds out that the agent should send a smiley, it creates a telegram (SmileyTelegram), and sends it to SmileyScheduler. SmileyScheduler keeps all the smiley telegrams (smiley requirements in a sense) in the order of priority, be sure that all telegrams in the list is still valid, and when the agent is available and the time is right, the scheduler makes the request from SmileyManager.

So, all these lines are basically motivation behind and the summary of how the system works. You can find more detail below, or on my GitHub page.

C++ Callbacks

There are many ways to handle callbacks in C++, but I prefer to use std::function polymorphic function wrapper with the help of std::bind. Because, the function wrapper makes the things very straight forward. You just need to keep a std::vector of the callbacks and when the time arrives, iterate through the vector and call the callbacks.

Here are some code pieces that handle adding the callbacks into the vectors and call them when the event is sent:

You can also check SmileyLogic to see how it registers itself to SmileyManager for receiving callOnFrame() calls.

Messaging System

When SmileyLogic feels that it needs to send a smiley, it prepares a SmileyTelegram and asks SmileyScheduler to handle it. The situation is like giving a package to a shipping company now. After you give the package, it is out of your control. The company makes a schedule, ships it, makes the package arrive to the desired destination, or magically get lost  on the road. It is same for SmileyScheduler too. After it receives a SmileyTelegram, it puts the telegram into a priority list (std::set in our case), and handles the list in its callOnFrame() method. It removes the invalid telegrams from the list, or makes the request if the agent is in a situation that it can send a smiley.

I am not sharing any piece of code in here since it will be long. But, you can see it on my GitHub page: GitHub/mcihanozer/C++_Callbacks_N_Messaging_System