Unity Event Dispatcher
Typed signals dispatched through a service, with auto-registration support and no static singletons.
What the system is for
Loose coupling in Unity usually starts with C# events. Then UnityEvents appear in the Inspector. Then a custom message bus shows up because no one wants to wire UnityEvents one by one across scenes. Each project ends up with its own variant of the same idea, and the resulting code still leaks references between systems that should not know about each other.
The Event Dispatcher in Serenity is the foundation's standard way of dispatching signals. It is service-based, signals are typed, and actions can be auto-registered through an attribute. Every other system in the foundation uses it, so signals are not bolted on, they are how the systems talk to each other.
The Unity problem
Unity events come in too many flavors and none of them are quite right for cross-system communication. C# events are simple but easy to leak. UnityEvents are visible in the Inspector but resist refactoring. Static event buses are convenient but fight unit tests. None of them encourage typed payloads, and all of them tend to grow organically until the dependency graph between systems is impossible to draw.
On top of that, registration is the part everyone forgets. Subscriptions are easy to add and easy to leak. When a system needs to listen for a signal, finding the right moment to register and the right moment to unregister tends to be tedious enough that people skip it.
How Serenity approaches it
Serenity exposes the event layer through IEventDispatcherService, with IEventDispatcherAction for handlers and EventDispatcherSignal for the typed signal contract. Auto-registration is supported through AutoRegisterEventActionAttribute, so actions can be discovered and registered by the installer instead of by hand-rolled code.
The Unity implementation is UnityEventDispatcherService, registered through UnityEventDispatcherInstaller. The dispatcher is a service, not a static singleton. Tests can replace it. Other systems resolve it through the interface and never reach for a global.
Diagnostics are first-class. The infrastructure layer ships UnityFileLogService and UnityFileLogSettings, registered through UnityFileLogInstaller, so signal flow can be written to a log file during development. When something goes wrong, you can see the actual signals that fired and the order in which they were handled.
How it fits into Serenity
Event Dispatcher lives in the Serenity.EventDispatcher namespace. Domain entities such as EventDispatcherSignal and EventDispatcherSignalDelegate describe the contract. The Application layer exposes the service and action interfaces. The Infrastructure layer provides UnityEventDispatcherService along with the file log service used for diagnostics through UnityFileLogService and UnityFileLogSettings.
Every other foundation system uses the dispatcher to communicate. Menus emit OnMenuSubmitOptionSignal. Modals emit OnShowModalSignal, OnCloseModalSignal and OnModalSubmitOptionSignal. Game Mode emits StartGameSignal, EnterMenuSignal and GameModeChangedSignal. Audio Player and Music Player emit PlayAudioClipSignal and PlayMusicTrackSignal. Game Settings emits OnGameSettingsOnValueUpdatedSignal. The dispatcher is the connective tissue that keeps these systems decoupled.
Practical workflow
- Define your signal type as a class that extends EventDispatcherSignal.
- Define an action that implements IEventDispatcherAction for that signal.
- Decorate the action with AutoRegisterEventActionAttribute if you want the installer to discover it.
- Dispatch the signal through the IEventDispatcherService from the code that wants to notify.
- Subscribe through actions or registered delegates from the code that wants to react.
- Replace the service in tests if you need to assert that a signal was raised.
What you get
- Service-based dispatcher IEventDispatcherService with no static singletons
- Typed signal contract through EventDispatcherSignal and EventDispatcherSignalDelegate
- Action interface IEventDispatcherAction for reactive handlers
- Auto-registration support via AutoRegisterEventActionAttribute
- Unity implementation UnityEventDispatcherService with installer registration
- Diagnostics through UnityFileLogService and UnityFileLogSettings
- Used as the connective layer across every other Serenity system
- Testable in isolation because the service is resolved through an interface
When to use this
- Projects that want gameplay systems to communicate without referencing each other.
- Teams that prefer typed signals over UnityEvents or raw C# events for cross-system messaging.
- Codebases moving away from static event buses toward a resolvable service.
- Games that need diagnostics or replay of event flow during development.
Related systems
Use Serenity when you want a typed event layer that the rest of the foundation already speaks, but still lets you define your own signals and actions for your game.
English
Español
Català