In this lecture, we'll refactor our talker and listener game again, to get an even better object oriented design. The big idea is that we'll add an event manager utility class that will make it so that the talker and the listener don't need to know about each other. They'll just interact with the Event Manager. We'll gain other benefits as well. We won't care what order they're added to the map when the game starts, and we'll be able to spawn and remove both broadcasters and listeners as the game plays, and everything will work fine. I will actually use the term Invokers rather than broadcasters, but the ideas are the same. Let's go see how we can reap these benefits from adding an Event Manager. I started with our unreal project from the previous lecture, and I've added two classes to the project. I've added a delegate declarations class that just a UObject and I added an Event Manager Actor that's an actor. And I turned the Event Manager Actor into a blueprint, and I added it to our scene. In I added an Event Manager game play tag to the project and tagged to this blueprint with that tag. Let's go take a look at the code. I added the delegate declarations class, just as a container for delegate declarations. I know as we build larger and larger games, we may have multiple delegates in our games. And although it's reasonable like we've seen previously to have the talker actor actually declare the delegate that the talker actor will broadcast. I decided to just group all our delegates for the game in this class instead, and grouping one in this class is not very exciting. But as we have more delegates, as you'll see in the next module, it's nicer to just put them all together in one place. So I've started doing that now. I've declared a one parameter multicast delegate, and I've called it FMessageEvent like we called it before and it has one parameter an FString, just like before. So this delegate declaration hasn't changed except I turned it into a multicast delegate instead of an event, because I'm also going to find that I will regularly have multiple classes that I want to broadcast the same event. So my standard will be to make them all multicast delegates. I'll call them events when I'm talking about them because that's how I think about them, but there'll be multicast delegates. So any class can broadcast the FMessageEvent. My Event Manager Actor, pound includes the talker actor and pound includes the listener actor and pound includes this header file as well. I have two fields in the Event Manager Actor. The first one is a TArray of pointers to talker actors. So this is a TArray of the Invoker of the event, in this makes it so that I can support having multiple talker actors in my map and they can all invoke the message event. The other property I have and here's why we talked about maps. This map is for message event listeners. In the key is a pointer to a listener actor. So again, I can have multiple listener actors in my map. I don't mean this map I mean a level in the game, and each of them will have a unique key of course because they each have a unique address. So I'll have an entry in this listeners map for each listener actor. And then the value is another map that I will key by a pointer to the talker actor and the value here will be an FDelegate handle. The reason I've structured it this way is so that listeners don't have to hold on to that FDelegate handle. Remember, we needed to hold on to that to be able to remove ourselves as a listener from the delegate when we get removed from the map. I didn't want the listeners to have to care about that detail. So I'm going to maintain this map here. So, when a listener says they want to be removed, we can effectively do that, removing them from each of the Invokers using the delegate handles that we saved in this map. We have the standard constructor begin, play and tick. And here's the new stuff. I'm going to let ATalkerActor add themselves as an Invoker of the message event. And I'm going to let ATalkerActor remove themselves as an Invoker of the event, in case that TalkerActor is getting removed from the level in the game. I'm going to let AListenerActor add themselves as a listener, I'm going to let a listener actor remove themselves as a listener, when the listener actor is getting removed from that level in the game. So the Event Manager will let Invokers add themselves as Invokers and the Invoker is don't have to know anything about who's listening for this particular event. Similarly, we'll let listeners add themselves as listeners. And the listeners don't have to know anything about who's going to invoke or broadcast the event. So this is a great way to decouple the classes that listen for events and the classes that broadcast events. We'll let the Event Manager do all the hooking up between Invoker and listeners in the body of our Event Manager Actor. Adding an Invoker, the first thing we do is we add the Invoker that's been passed in to the TArray of message event Invokers. The next thing we want to do is because we don't know if there are listeners who have already added themselves as listeners, we want to go through the map of message event listeners and add each of them as a listener for this new Invoker. When this new Invoker broadcasts the event, I'm using a range based for loop to do this. So the element I'm looking at each time through the loop is called element. I'm going to execute this for loop across the map of message event listeners. This is new, we haven't actually talked about auto, but auto is just a way to say, I'm not going to tell you what type this element is. I'm going to let the compiler infer from this information specifically from this, what each element will be as we go through the for loop. And this of course just says we want to reference to that particular type. You may wish I had told you about auto before, it certainly shortens this line of code. But I wanted us to spend a lot of time in the previous courses thinking about the actual data types that we were dealing with. So I didn't tell you about auto until now, but I think you're mature enough as C++ programmers and unreal game developers to be able to handle letting the compiler just infer the data type. The next line of code, we take the element we're looking at, and we take the key for that element and the key for that element is a pointer to an AListenerActor. Then we're going to call a function on that AListenerActor that says, add to message event. So we're going to pass in a message event into the a listener actor. And the AListenerActor will add the address of its callback function to the message event, we pass in. To get the message event we pass in, we have a pointer to an Invoker that we passed in as a parameter up here. And we call the GetMessageEvent function on the ATalkerActor to get the MessageEvent that is embedded in the Invoker. I need the FMessageEvent field private in the talker actor just because that's the way it really ought to be. But I provided together so that we can get access to that FMessageEvent. So this is just adding a listener to the MessageEvent inside the Invoker. And then the final line here is, I tick the ElementValue, which remember is another map, that map's pointers to ATalkerActors as keys, and FDelegateHandles as values. And I add, an element to that map, using the Invoker as my key, and the DelegateHandle that I just got here as my value. And we're only doing that so that we can remove the listener later if we need to do that. So that's how we add an Invoker. Big picture again, we add the Invoker to the TArray of Invoker of the MessageEvent. And then we iterate over the map of MessageEventListeners who have already added themselves as listeners. And we make sure they're listening for the event being broadcast from this new Invoker that we just added. To remove an Invoker, the first thing we do is we remove all listeners from the Invoker. So we execute a for loop over all the MessageEventListeners, and if the map that map's Invoker to DelegateHandles contains this particular Invoker. Then we get the MessageEvent from the Invoker, and then we remove this particular listener by accessing the value in the map. And that value, remember is an FDelegateHandle. So this is how we remove the current listener we're working on from the event in the Invoker. And then we remove that element from the map because the Invoker's getting removed so we don't need this element in the map anymore. With this particular Invoker as the key and the DelegateHandle we used when we added to this message of end as the value. So this is removing that element from the map. Now that we've disconnected all the listeners from this Invoker, we actually removed this Invoker from the TArray of Invoke for the MessageEvent. To add a new listener, we do something similar to adding a new Invoker. The first thing we do is we add the listener to the map of listeners, and then we iterate over all the Invokers. And for each Invoker, we hook up this new listener to the set of Invokers who have already said they're Invokers of the event. So this code right here does what we saw previously, we're hooking up this listener to the current Invoker we're looking at as element. And then we add to the map of Invoker pointers, and FDelegateHandles, the delegate and handle we just got. With the current Invoker we're looking at as the key and the delegate handle as the value. Remember, we do that so we can remove the listener later. And that's all we have to do to add the listener. To big picture, we add the listener to the map of listeners. And then for each of the existing Invokers we go through and we hook up this listener to that InvokersMessageEvent. Finally, removing a listener looks a lot like removing an Invoker. We go through all the Invokers. If the map in the listener contains the Invoker that we're currently looking at as a key, then we remove this listener as a listener for the event for that particular Invoker. And then we remove that element in our map of ATalkerActor pointers and FDelegateHandles because we just disconnected this listener from that Invoker. So we don't need that element in the map anymore. And then finally when we've done all that disconnecting to says remove Invoker but let me fix that, we remove the listener. So that's all the stuff in the Event Manager. We can move a little more quickly now in our talker actor, we need to pound include our delegate declarations so that we have a reference to that delegate that we defined over there. And here's where I have a field for that FMessageEvent. I've added that GetMessageEvent function that we've been talking about. And it's really important that this returns a reference to an FMessageEvent because we need to make sure that we're not returning a copy of the FMessageEvent. We need to get a reference to the FMessageEvent to make sure that when we do this and we're hooking up a listener to this talker, that we make sure that we're doing it with the FMessageEvent field, not a copy of the FMessageEvent field. And EndPlay, just as we saw in not the previous lecture, but the lecture before that. In my implementation for the TalkerActor, I do more work in BeginPlay now because I need to add myself as an Invoker to the Event Manager. So, as I said I tagged to the Event Manager with this tag so I do our standard go find a tagged actor, and if I find it I cast that a actor pointer to a pointer to an Event Manager Actor. And then finally I call the AddInvoker function that we looked at passing myself in as the Invoker. Down here, I haven't changed my talk function at all, I still broadcast the message event. And when I'm being removed from the level, I go find the EventManager again and I remove myself as an Invoker, and that's it for the talker actor. For the listener actor, I pound include delegate declarations again I have that AddToMessageEvent function that we talked about the receive message function we already saw previously, and the EndPlay function we saw previously. So in my implementation file, when the BeginPlay, I find the Event Manager, and add myself as AListener. Here's that new AddToMessageEvent function where I just call the AddUObject function on our MessageEvent. Passing myself in is the object in the address of my ReceiveMessage function as the callback function. And I returned the FDelegateHandle that I get back from calling AddUObject so that the Event Manager can add that to the map that contains talker actor pointers and FDelegateHandles. I didn't change receive message at all. And here on EndPlay, I find the Event Manager again and remove myself as a listener. And just to show you that the game works fine with this new event manager structure. And when I run my game, you can see that the listener actor is still receiving those messages, and the talker actor is still broadcasting those messages. That's how the listener actor can receive them. But we connected those two together through the Event Manager rather than having the listener directly know that the talker actor was the one who is broadcasting that event. And having the listener actor interact directly with the talker actor. To recap, in this lecture you learned how to add an event manager utility class to gain a number of benefits as we handle events in our games. And doing it this way, gives us a really solid object oriented design.