Decoupled, simple systems.
Connect gameplay systems without direct references between senders and receivers. Untargeted, targeted, and broadcast messages keep those systems independent, testable, and observable, while struct messages keep steady-state dispatch allocation-free.
Free forever. No paid editions, paid upgrades, or feature charges. Read the AI assistance disclosure.
using DxMessaging.Core.Attributes;
using DxMessaging.Core.Extensions;
using DxMessaging.Unity;
[DxUntargetedMessage]
[DxAutoConstructor]
public readonly partial struct GamePaused
{
public readonly bool IsPaused;
}
// PauseController announces the fact after owning the state change.
GamePaused gamePaused = new GamePaused(isPaused);
gamePaused.EmitUntargeted();
// PauseOverlay owns this UI registration.
Token.RegisterUntargeted<GamePaused>(OnPauseOverlayChanged);
// MusicDirector owns a separate audio registration.
Token.RegisterUntargeted<GamePaused>(OnMusicPauseChanged);
using DxMessaging.Core.Attributes;
using DxMessaging.Core.Extensions;
using DxMessaging.Unity;
[DxTargetedMessage]
[DxAutoConstructor]
public readonly partial struct Heal
{
public readonly int Amount;
}
// Register on the player that can receive heals.
Token.RegisterGameObjectTargeted<Heal>(gameObject, OnHeal);
// Send from any system.
Heal heal = new Heal(50);
heal.EmitGameObjectTargeted(player);
using DxMessaging.Core.Attributes;
using DxMessaging.Core.Extensions;
using DxMessaging.Unity;
[DxBroadcastMessage]
[DxAutoConstructor]
public readonly partial struct CollisionOccurred
{
public readonly float Speed;
}
// CollisionReporter emits from the GameObject that collided.
CollisionOccurred collisionOccurred = new CollisionOccurred(speed);
collisionOccurred.EmitGameObjectBroadcast(gameObject);
// ImpactSound on the same GameObject owns this registration.
Token.RegisterGameObjectBroadcast<CollisionOccurred>(gameObject, OnImpactSound);
// BreakableObject on the same GameObject owns a separate registration.
Token.RegisterGameObjectBroadcast<CollisionOccurred>(gameObject, OnBreakableCollision);
The three message types
Announce to all
A global message with no sender and no target. Anything listening hears it. The PA system.
[DxUntargetedMessage] Command one
A message to one specific GameObject. Only that object receives it. The addressed letter.
[DxTargetedMessage] Emit a fact
A fact from a known source. Listeners can filter by who sent it. The radio station.
[DxBroadcastMessage] First Message
AI Assistance Disclosure¶
DxMessaging began as an original project around 2014 and remains actively developed and used today. Over the past two years, I (wallstop) have been using LLMs to help improve the library's quality and performance, expand its tests, and create user-facing documentation. There is always a human in the loop: I actively review all changes and read through all user-facing copy. I share this so you can make an informed decision about using the project.
DxMessaging is free and will remain free forever. No paid editions, paid upgrades, or feature charges.
Start Here¶
- Quick Start - Define, register, and emit your first message.
- Mental Model - Choose between untargeted, targeted, and broadcast messages.
- Message Monitor - Inspect emissions, filters, contexts, and captured call sites.
- Flow Graph - Inspect loaded-scene
MessagingComponentroutes and delivery evidence. - Inspector Tools - Catch base-call mistakes and inspect component-local diagnostics.
- Performance - Read the current published benchmark tables.
Install¶
OpenUPM¶
Git URL¶
See the Install Guide for scoped registry, Git URL, and local tarball options.
Why Teams Use It¶
Simple primitives
Three message shapes - untargeted, targeted, broadcast - and nothing else to learn. Each contract is an explicit typed struct, and no system holds a reference to any other.
Easy to use
Define a struct, register a handler, emit. Registration tokens follow their owner's lifecycle, so handlers remove themselves - no manual unsubscribe, no leaked listeners.
Small edits, big impact
The same simple primitives decouple entire systems. Wiring a feature in is one registration; removing it is deleting that line. Interceptors, handler priorities, and global observers layer on without touching existing code.
High performance
Struct messages and readonly by-reference handlers keep steady-state dispatch at zero allocation. Type-indexed routing stays O(1); see the current CI table for measured scenario costs.
Next¶
- New to the package: Getting Started
- Choosing message types: Message Types
- Unity integration patterns: Unity Integration
- Debugging message flow: Diagnostics
- API details: Reference