Overview
EventHub is a project-wide publish/subscribe event bus. Any Blueprint or C++ object can emit an event and any other object can listen for it, without either side holding a reference to the other. It works across actors, components, widgets and sub-levels, which makes cross-Blueprint communication simple and keeps systems decoupled.
- Addressing: a Domain + Event string pair (for example
global.default/ScoreChanged) or a GameplayTag. Tag and string forms interoperate. - Wildcard payload: emit one value of any type - int, float, bool, byte, string, name, struct or object. Wrap arrays and maps in a struct.
- Pinned events are replayed to listeners that bind after the emit, so an event can carry state such as "level ready".
- Four ways to receive: a function bound by name, a wildcard delegate, a receiver component, or a C++ lambda.
- Type checking: a listener whose function does not take the emitted type is skipped with a descriptive warning in the log; other listeners still receive the event.
- Automatic cleanup of listeners whose objects were destroyed and of every event of a world when that world ends.
- Ready-made receiver components for Bool, Float, Int, Object, Rotator, String, Transform and Vector payloads.
Requirements
| Requirement | Details |
|---|---|
| Unreal Engine | 4.27 and 5.8 (verified clean on both) |
| Modules | EventHub (Runtime, loading phase Default) |
| Dependencies | None. Uses the engine module GameplayTags, which is always available. |
| Language | Blueprints and C++ |
| Platforms | No platform restriction in the plugin descriptor. Win64 is the platform built and verified by Alpha XP; other platforms are supported by the code, not verified by Alpha XP. |
Installation
- Copy the
EventHubfolder into your project'sPlugins/folder (create it if needed), or install the plugin to the engine from Fab. - Open the project. For a C++ project, let the editor build the module or build it from your IDE.
- Enable EventHub in Edit > Plugins (category Programming) and restart the editor.
- C++ only: add
"EventHub"toPublicDependencyModuleNamesin your module'sBuild.cs(add"GameplayTags"as well if you use tag-based calls).
GenericComponentReceivers and Macros.Quick start
Blueprint
- In the receiving Blueprint, create a custom event (or function) with one input of the type you will send, for example
OnScoreChangedwith anIntegerinput namedScore. - On Event BeginPlay, call EHBind Event with Domain
global.default, EventScoreChangedand Receiving FunctionOnScoreChanged. - In the emitting Blueprint, call EHEmit Event One Param with the same Domain and Event and connect an integer to Parameter Data.
- On Event EndPlay of the receiver, call EHUnbind All Events For Context (or EHUnbind Event).
For events without data use EHEmit Event and a receiving event with no inputs. Tick Pinned on the emit to replay the event to listeners that bind later.
C++
#include "EHHandler.h"
void AMyActor::BeginPlay()
{
Super::BeginPlay();
// Listen with a typed lambda
FEHEventContext Listen;
Listen.Domain = TEXT("global.default");
Listen.Event = TEXT("ScoreChanged");
Listen.WorldContext = this;
ScoreListenerId = FEHHandler::DefaultHandler()->AddLambdaListenerInt(Listen, [](int32 Score)
{
UE_LOG(LogTemp, Log, TEXT("Score is now %d"), Score);
});
}
void AMyActor::AddScore()
{
// Emit an int32 payload
FEHEmitContext Emit;
Emit.Domain = TEXT("global.default");
Emit.Event = TEXT("ScoreChanged");
Emit.WorldContext = this;
Emit.bPinned = false;
FEHHandler::DefaultHandler()->EmitEvent(Emit, 42);
}
void AMyActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
FEHEventContext Listen;
Listen.Domain = TEXT("global.default");
Listen.Event = TEXT("ScoreChanged");
Listen.WorldContext = this;
FEHHandler::DefaultHandler()->RemoveLambdaListener(Listen, ScoreListenerId); // FString ScoreListenerId member
Super::EndPlay(EndPlayReason);
}
Concepts
Domain and Event
Every event is identified by a Domain (a channel, default global.default) and an Event name. Listeners only receive events with exactly the same pair.
GameplayTags
Tag-based nodes split the tag at its last dot: Game.Player.Died becomes domain Game.Player and event Died. A tag without a dot uses domain global.default. A tag emit therefore reaches string-based listeners of the same pair and the other way round. To Domain and Event (GameplayTag) shows the split.
Payload
One value of any Blueprint type. The receiving function must take exactly one parameter of the same type (or none for events without data). Arrays, maps and sets cannot be emitted directly; wrap them in a struct. Struct types are validated by default (see Set EHOptions).
Pinning
An event emitted with Pinned keeps its last value: listeners that bind later receive it immediately when they bind. Use EHUnpin Event to stop replaying it. To pin a different value, unpin the old one first.
Lifetime
Listeners are tracked per world. When a world ends, all of its events and listeners are removed (a hidden helper actor, AEHWorldListenerActor, is spawned per world for this). Listeners whose objects are destroyed are removed when they are found stale. In the editor, all events are cleared when a Play-In-Editor session starts.
Emitting events
Category EventHub. All emit nodes take a world context automatically.
| Node | Type | Description |
|---|---|---|
| EHEmit Event | Callable | Emits an event without data. Inputs: Pinned, Domain (default global.default), Event. |
| EHEmit Event One Param | Callable | Emits an event with one wildcard value (Parameter Data accepts any type). Inputs: Parameter Data, Pinned, Domain, Event. |
| EHEmit Tag Event | Callable | Emits an event without data, addressed by a GameplayTag (Domained Event Tag). |
| EHEmit Tag Event One Param | Callable | Emits an event with one wildcard value, addressed by a GameplayTag. |
| EHUnpin Event | Callable | Stops replaying a pinned event to future listeners. |
Binding and unbinding
| Node | Type | Description |
|---|---|---|
| EHBind Event | Callable | Binds a function or custom event of the calling Blueprint, given by name in Receiving Function, to Domain + Event. |
| EHBind Tag Event | Callable | Same as EHBind Event, addressed by a GameplayTag. |
| EHBind Event To Delegate | Callable | Binds an event delegate (connect a custom event with one Wildcard Property input). Read the value with the conversion nodes below. |
| EHBind Tag Event To Delegate | Callable | Delegate binding addressed by a GameplayTag. |
| EHUnbind Event | Callable | Removes a function binding made with EHBind Event. |
| EHUnbind Tag Event | Callable | Removes a function binding addressed by a GameplayTag. |
| EHUnbind Delegate | Callable | Removes a delegate binding. |
| EHUnbind Tag Delegate | Callable | Removes a delegate binding addressed by a GameplayTag. |
| EHUnbind All Events For Context | Callable | Removes every binding owned by Context (the calling object when left empty). Call it on EndPlay. |
All bind and unbind nodes can be found by searching for eventhub, listen or stoplisten.
Wildcard conversions
Category Utilities > EventHub. Used with delegate bindings and with LastReceivedProperty of the receiver component. Each returns true when the stored value has the requested type (except the plain string conversion). Most of them are auto-cast nodes: dragging a Wildcard Property pin onto a typed input inserts them automatically.
| Node | Type | Description |
|---|---|---|
| To Integer (Wildcard Property) | Pure | Reads the value as an integer. |
| To Float (Wildcard Property) | Pure | Reads the value as a float. |
| To Bool (Wildcard Property) | Pure | Reads the value as a bool. |
| To String (Wildcard Property) | Pure | Converts the value to a string (for printing); warns in the log on failure. |
| To String Ref with status (Wildcard Property) | Pure | Converts the value to a string and returns whether it succeeded. |
| To Name (Wildcard Property) | Pure | Reads the value as a Name. |
| To Struct (Wildcard Property) | Pure | Copies the value into a struct of the connected type (wildcard output). |
| To Object (Wildcard Property) | Pure | Reads the value as an object reference. |
| To Domain and Event (GameplayTag) | Pure | Splits a GameplayTag into its Domain and Event strings. |
Options
| Node / field | Default | Description |
|---|---|---|
| Set EHOptions | - | Callable, category EventHubOptions. Applies an FEHGlobalOptions struct to the global handler. |
| bValidateStructTypes | true | Checks that emitted structs exactly match the receiving parameter type. Turn off for a small speed gain. |
| bLogStaleRemovals | true | Logs listeners and events removed because their objects or worlds are gone. |
Receiver components
UEHBaseReceiverComponent (Blueprintable, spawnable from Add Component, class group Utility) binds itself on BeginPlay and unbinds on EndPlay.
| Property | Type | Description |
|---|---|---|
| OnEvent | Event | Wildcard event dispatcher called with the received value when Receiving Function is left at its default OnEvent(component). |
| BindSettings | FEHNameBind | Domain (default global.default), Event and Receiving Function. With another function name, that function on the component itself (for example a custom event in a Blueprint subclass of the component) is bound instead of OnEvent. |
| LastReceivedProperty | Wildcard | Last received value, for polling with the conversion nodes. |
| bBindOnBeginPlay | bool, true | Binds automatically on BeginPlay. |
| bUnbindOnEndPlay | bool, true | Unbinds automatically on EndPlay. |
| bPinInternalDataForPolling | bool, true | Keeps a copy of the received value so LastReceivedProperty stays valid. |
| bDidReceiveEventAtLeastOnce | bool | True once an event has been received (polling is valid). |
C++ API
Include EHHandler.h and use the global handler FEHHandler::DefaultHandler(). Emits take an FEHEmitContext (Domain, Event, WorldContext, bPinned); listeners take an FEHEventContext (Domain, Event, WorldContext).
| Function | Kind | Description |
|---|---|---|
| DefaultHandler | static | Returns the global TSharedPtr<FEHHandler>. |
| EmitEvent | C++ | Overloads for no payload, UStruct* + pointer, FString, TEXT("") literals, UObject*, float, int32, bool and FName. |
| AddLambdaListener | C++ | Typed overloads for wildcard (const FEHWildcardProperty&), struct (UStruct*, void*), FString, UObject*, float, FName and no payload. Returns a listener id. |
| AddLambdaListenerInt / AddLambdaListenerBool | C++ | Integer and bool listeners (separate names avoid ambiguity with float). |
| RemoveLambdaListener | C++ | Removes a lambda listener by the id returned when it was added. |
| AddListener / RemoveListener | C++ | Generic listener binding used by the Blueprint nodes. |
| RemoveAllListenersForReceiver | C++ | Removes every listener owned by an object. |
| CreateEvent / DeleteEvent / HasEvent | C++ | Explicit event management. |
| UnpinEvent | C++ | Stops replaying a pinned event. |
| SetOptions | C++ | Applies FEHGlobalOptions. |
| Clear | static | Removes all events and listeners. |
| UEventHubBPLibrary | Class | The Blueprint function library; its static functions (EHBindEvent, EHEmitEvent ...) can be called from C++ too. |
Content
Plugin content (enable Show Plugin Content in the Content Browser view options).
| Asset | Type | Description |
|---|---|---|
| BoolEHReceiverComponent | Blueprint | Receiver component for bool payloads: event dispatcher On Bool Received, variable Last Value. |
| FloatEHReceiverComponent | Blueprint | Receiver for float payloads (On Float Received, Last Value). |
| IntEHReceiverComponent | Blueprint | Receiver for integer payloads (On Int Received, Last Value). |
| ObjectEHReceiverComponent | Blueprint | Receiver for object payloads (On Object Received, Last Value). |
| RotatorEHReceiverComponent | Blueprint | Receiver for rotator payloads (On Rotator Received, Last Value). |
| StringEHReceiverComponent | Blueprint | Receiver for string payloads (On String Received, Last Value). |
| TransformEHReceiverComponent | Blueprint | Receiver for transform payloads (On Transform Received, Last Value). |
| VectorEHReceiverComponent | Blueprint | Receiver for vector payloads (On Vector Received, Last Value). |
| EHMacroLibrary | Macro library | Small Blueprint macro library with a general-purpose flow helper. |
The eight receiver components live in GenericComponentReceivers and derive from EHBaseReceiverComponent. Add one to an actor, set Bind Settings (Domain and Event) and bind to its On ... Received dispatcher. EHMacroLibrary lives in Macros.
Troubleshooting
| Symptom | Cause and fix |
|---|---|
| The receiving function is never called | Domain and Event must match exactly (case-sensitive strings), the receiver must be bound before a non-pinned emit happens, and Receiving Function must be the exact name of a function or custom event on the bound object. A warning in the log reports a missing function. |
| Log: listener skipped due to function not having a matching signature | The receiving function's single parameter does not match the emitted type. Change the parameter type, or bind with EHBind Event To Delegate and convert the wildcard value. |
| Struct payload rejected | With bValidateStructTypes enabled, the receiving struct type must be exactly the emitted struct type. |
| Arrays or maps cannot be connected to Parameter Data | Containers are not supported as a payload. Wrap them in a struct and emit the struct. |
| Late listeners miss an event | Emit it with Pinned enabled so it is replayed to listeners that bind afterwards; call EHUnpin Event when the state is no longer valid. |
| Events received after a level change or by destroyed actors | Unbind on EndPlay with EHUnbind All Events For Context. Events of a world are removed automatically when that world ends. |
| Events do not reach other players | EventHub works inside one game instance. Use replicated properties or RPCs to cross the network, then emit locally on each machine. |
Credits
© 2026 Alpha XP — alphaxp.net · Support: support@alphaxp.net. Built and verified for Unreal Engine 4.27 and 5.8.