It’s the same thing in UE terminology - the only implementation detail missing is the idea of the central object which manages them, but that’s very simple to implement yourself.
In UE, ANY class can Bind (subscribe) to a delegate/event, and any class can Broadcast (publish/call) a delegate. Events restrict the caller/publisher to the owning class, delegates do not, that’s the only different between them.
The engine does this in at least two ways I can think of:
- static members (easily accessible from anywhere)
- easily-accessible class instances (such as subsystems), which hold delegate members. These class instances are usually statically accessible in some way.
Making them accessible cross-module is as easy as tagging them for dll export.
This is extremely common practice in UE to allow game-level code to push out events that user-interface can respond to, or in multiplayer where you may have race conditions between actors etc. Ultimately it’s the same thing - unrelated classes can find and bind to events, and other unrelated classes can broadcast them, and neither object at either end has to know about implementation details of the other.