Plugin Documentation

EventHub
Project-wide event bus for Blueprints and C++

Emit events by Domain and Event name or by GameplayTag, with any single value as payload, and receive them anywhere - by function name, wildcard delegate, receiver component or C++ lambda - without references between objects.

v1.0
UE 4.27 & 5.8
Win64 (verified)
Category Programming
Alpha XP

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.
Local, synchronous deliveryEmits run every listener before the emit call returns. Events stay inside the local game instance; they are not replicated or sent over the network.

Requirements

RequirementDetails
Unreal Engine4.27 and 5.8 (verified clean on both)
ModulesEventHub (Runtime, loading phase Default)
DependenciesNone. Uses the engine module GameplayTags, which is always available.
LanguageBlueprints and C++
PlatformsNo 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

  1. Copy the EventHub folder into your project's Plugins/ folder (create it if needed), or install the plugin to the engine from Fab.
  2. Open the project. For a C++ project, let the editor build the module or build it from your IDE.
  3. Enable EventHub in Edit > Plugins (category Programming) and restart the editor.
  4. C++ only: add "EventHub" to PublicDependencyModuleNames in your module's Build.cs (add "GameplayTags" as well if you use tag-based calls).
Verifying the installRight-click in any Blueprint graph and search for eventhub: the EventHub category lists the bind, emit and unbind nodes. In the Content Browser, enable Show Plugin Content to see the EventHub content folder with GenericComponentReceivers and Macros.

Quick start

Blueprint

  1. In the receiving Blueprint, create a custom event (or function) with one input of the type you will send, for example OnScoreChanged with an Integer input named Score.
  2. On Event BeginPlay, call EHBind Event with Domain global.default, Event ScoreChanged and Receiving Function OnScoreChanged.
  3. In the emitting Blueprint, call EHEmit Event One Param with the same Domain and Event and connect an integer to Parameter Data.
  4. 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.

NodeTypeDescription
EHEmit EventCallableEmits an event without data. Inputs: Pinned, Domain (default global.default), Event.
EHEmit Event One ParamCallableEmits an event with one wildcard value (Parameter Data accepts any type). Inputs: Parameter Data, Pinned, Domain, Event.
EHEmit Tag EventCallableEmits an event without data, addressed by a GameplayTag (Domained Event Tag).
EHEmit Tag Event One ParamCallableEmits an event with one wildcard value, addressed by a GameplayTag.
EHUnpin EventCallableStops replaying a pinned event to future listeners.

Binding and unbinding

NodeTypeDescription
EHBind EventCallableBinds a function or custom event of the calling Blueprint, given by name in Receiving Function, to Domain + Event.
EHBind Tag EventCallableSame as EHBind Event, addressed by a GameplayTag.
EHBind Event To DelegateCallableBinds an event delegate (connect a custom event with one Wildcard Property input). Read the value with the conversion nodes below.
EHBind Tag Event To DelegateCallableDelegate binding addressed by a GameplayTag.
EHUnbind EventCallableRemoves a function binding made with EHBind Event.
EHUnbind Tag EventCallableRemoves a function binding addressed by a GameplayTag.
EHUnbind DelegateCallableRemoves a delegate binding.
EHUnbind Tag DelegateCallableRemoves a delegate binding addressed by a GameplayTag.
EHUnbind All Events For ContextCallableRemoves 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.

NodeTypeDescription
To Integer (Wildcard Property)PureReads the value as an integer.
To Float (Wildcard Property)PureReads the value as a float.
To Bool (Wildcard Property)PureReads the value as a bool.
To String (Wildcard Property)PureConverts the value to a string (for printing); warns in the log on failure.
To String Ref with status (Wildcard Property)PureConverts the value to a string and returns whether it succeeded.
To Name (Wildcard Property)PureReads the value as a Name.
To Struct (Wildcard Property)PureCopies the value into a struct of the connected type (wildcard output).
To Object (Wildcard Property)PureReads the value as an object reference.
To Domain and Event (GameplayTag)PureSplits a GameplayTag into its Domain and Event strings.

Options

Node / fieldDefaultDescription
Set EHOptions-Callable, category EventHubOptions. Applies an FEHGlobalOptions struct to the global handler.
bValidateStructTypestrueChecks that emitted structs exactly match the receiving parameter type. Turn off for a small speed gain.
bLogStaleRemovalstrueLogs 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.

PropertyTypeDescription
OnEventEventWildcard event dispatcher called with the received value when Receiving Function is left at its default OnEvent(component).
BindSettingsFEHNameBindDomain (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.
LastReceivedPropertyWildcardLast received value, for polling with the conversion nodes.
bBindOnBeginPlaybool, trueBinds automatically on BeginPlay.
bUnbindOnEndPlaybool, trueUnbinds automatically on EndPlay.
bPinInternalDataForPollingbool, trueKeeps a copy of the received value so LastReceivedProperty stays valid.
bDidReceiveEventAtLeastOnceboolTrue 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).

FunctionKindDescription
DefaultHandlerstaticReturns the global TSharedPtr<FEHHandler>.
EmitEventC++Overloads for no payload, UStruct* + pointer, FString, TEXT("") literals, UObject*, float, int32, bool and FName.
AddLambdaListenerC++Typed overloads for wildcard (const FEHWildcardProperty&), struct (UStruct*, void*), FString, UObject*, float, FName and no payload. Returns a listener id.
AddLambdaListenerInt / AddLambdaListenerBoolC++Integer and bool listeners (separate names avoid ambiguity with float).
RemoveLambdaListenerC++Removes a lambda listener by the id returned when it was added.
AddListener / RemoveListenerC++Generic listener binding used by the Blueprint nodes.
RemoveAllListenersForReceiverC++Removes every listener owned by an object.
CreateEvent / DeleteEvent / HasEventC++Explicit event management.
UnpinEventC++Stops replaying a pinned event.
SetOptionsC++Applies FEHGlobalOptions.
ClearstaticRemoves all events and listeners.
UEventHubBPLibraryClassThe 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).

AssetTypeDescription
BoolEHReceiverComponentBlueprintReceiver component for bool payloads: event dispatcher On Bool Received, variable Last Value.
FloatEHReceiverComponentBlueprintReceiver for float payloads (On Float Received, Last Value).
IntEHReceiverComponentBlueprintReceiver for integer payloads (On Int Received, Last Value).
ObjectEHReceiverComponentBlueprintReceiver for object payloads (On Object Received, Last Value).
RotatorEHReceiverComponentBlueprintReceiver for rotator payloads (On Rotator Received, Last Value).
StringEHReceiverComponentBlueprintReceiver for string payloads (On String Received, Last Value).
TransformEHReceiverComponentBlueprintReceiver for transform payloads (On Transform Received, Last Value).
VectorEHReceiverComponentBlueprintReceiver for vector payloads (On Vector Received, Last Value).
EHMacroLibraryMacro librarySmall 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

SymptomCause and fix
The receiving function is never calledDomain 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 signatureThe 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 rejectedWith bValidateStructTypes enabled, the receiving struct type must be exactly the emitted struct type.
Arrays or maps cannot be connected to Parameter DataContainers are not supported as a payload. Wrap them in a struct and emit the struct.
Late listeners miss an eventEmit 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 actorsUnbind on EndPlay with EHUnbind All Events For Context. Events of a world are removed automatically when that world ends.
Events do not reach other playersEventHub 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.