Deep Dive
In a few words, the Event Dispatcher Hub is a two-part plugin.
Objects can Bind themselves at runtime to specific Gameplay Tags that have to be setup as unique event identifiers; and whenever this Tag is called (by any Object), all bound objects will receive the call and are able to identify it, or trace it back to the source.
All credits for this concept go to
Knut Øverbye.
He is the original creator of the Event Dispatcher Hub as seen in his Roguelite Deckbuilder Toolkit plugin.
Using
only the Functions’ names and input/outputs as seen in his tutorial YouTube playlist, I
retro-engineered
(or at least created another version of) the inner workings of his plugin and coded it for my own personal use.
Buckle up, this Deep Dive is gonna be technical!
Why make this Plugin?
Unreal Engine has this system of “Event Dispatcher”. A way to Bind an Actor to an Event so that, whenever this Event is called, it gets notified and can do stuff.
All Actors bound to the Event receive the notification at the same time and do their own implementation. Think of it as a way to say “This stuff happened!” to all Actors that care about this stuff happening.
Problem #1: All Events are linked to an Actor
You can’t have an event that is not linked to a specific Actor (or Component). While in most scenarios you can think of an Actor that would be the source of the transmission (“I got damaged!”, “I finished charging!”…); it is needlessly restrictive.
Imagine you need to do something every time an enemy gets killed; you could have an Enemy Manager receiving the call and passing it on to the scoreboard, the player character, the particle manager, the environmental reactions… Or the enemy could just fire an Event Dispatcher Hub Event and everybody that needs to know when an enemy dies is happy.
This also means that you need to pay attention to which Actor has which Event, because you can’t call an Event if it is owned by a deleted Actor!
Problem #2: You NEED a Hard Reference to that Actor
The main source of the issue in my eyes, you’re obligated to get a reference to that owning Actor, and a Hard Reference on top of that. You need to have a Cast whether you want to Bind to OR Call an Event.
While getting a reference could be done by only Putting events on easy-to-access and always-loaded Objects like GameModes, PlayerPawns or PlayerStates (in which case Casts are less of an issue); this is another restriction that needs to be bypassed.
The need for a Hard Reference is the final nail in the coffin for optimization and code cleanliness.
Problem #3: Lack of Debugging Features
Want to know which Actors are bound to a certain Event? Or at least how many there are?
Want to know in which order they are called without tracking down every Actor with a binding and adding a print in their code?
None of this is doable with Blueprints in Unreal Engine.
Overview of the inner workings
The Plugin mainly consists in 3 parts:
- The Custom GameMode which should be the parent of whatever the final GameMode ends up being. It handles spawning the EventDispatcherHub before the BeginPlay is called, and sending to it the Binding/Calling requests.
- The Event Dispatcher Hub which stores all of the Events and their bound Objects and handles the Binding, Unbinding, and Calling requests.
- The Function Library and Interfaces that allow the reference-free and game-wide requests to Bind, Unbind, Call, and Receive events.

Simplified diagram of the Plugin’s functioning. Some details like the Call Queue or Dead Reference Removal are omitted for clarity’s sake.
Other Details
Call Queuing
To avoid cutting the ForEach loops in the middle of its work, there is a Queuing System going on.
When the Event Dispatcher Hub receives a Call request, it first checks if it isn’t in the middle of calling another Event. If it’s free, it just calls the Event as regular; but if it’s busy, it stores the call and deals with it later, when all of the previous Calls have been handled.
One at a time.
Reference Removal
To make the Event Dispatcher Hub more lightweight (it’s gonna reference ALL bound objects!!), it stores Objects as Soft References.
When trying to tell them that the Event is called, it first verifies if the reference still is valid (If the Object hasn’t been deleted); and if not, queues its deletion to prevent keeping dead references.
Since it’s a Soft reference, it doesn’t prevent the Garbage Dispatcher from doing its job of actually removing the object from memory once deleted.
Multi-Purpose calls and Called Object Access
Since the goal of the plugin is to be as versatile as possible, all Calls are received through a single Function in a single Interface.
Which Event is called is given with its GameplayTag—which can be separated thanks to a Switch, but there is no way to pass other data such as a float, a vector, or a string.
If we need to send a float; why not send a Vector to store 3 floats at once? But then why not a Transform for a total of 9 floats? An array of floats?… That soon becomes way too much data to pass for each edge case.
Then, how do we transmit String data? Actor References? Gameplay Tags? Structs?…
To remedy this, the Calling Object is passed through. If there is any data that needs to be transmitted, it can then be retrieved with a Cast, an Interface, a Component, or any other preferred method of data retrieval.

Example of the ReceiveEvent interface. You can know which Tag has been called and what Object called it.
Q&A
Can I get the plugin?
As I said up top, this whole plugin is based on Knut Øverbye‘s work; so it doesn’t feel right to release the plugin publicly.
I don’t personally consider this whole work “stealing” per se since I only had the input/output of some functions to go by. I recreated the inner workings without much to go off of, for personal use only, and it is originally part of a much bigger plugin (Roguelike Deckbuilder Toolkit); but this only holds up if it stays personal in my opinion.
Why is it Blueprint-only?
This isn’t a military-grade plugin designed in C++ for teams of 1500+ people. It’s a personal, custom plugin that I’m using to simplify my prototypes and group projects. The fact that it’s Blueprint makes the code readable by more people (including myself), and allows its implementation in quick Blueprint-only projects.