# Message Types: When and How to Use [Back to Index](../getting-started/index.md) | [Getting Started](../getting-started/getting-started.md) | [Patterns](../guides/patterns.md) | [Visual Guide](../getting-started/visual-guide.md) --- This guide introduces the three message categories in DxMessaging with concepts, when to use them, and practical code. ## Overview - Untargeted: global notifications anyone can listen to (e.g., world regenerated). - Targeted: directed at one recipient (e.g., heal Player by 10). - Broadcast: emitted from a source for anyone to observe (e.g., Enemy took 5 damage). ### Quick Decision Guide ```mermaid flowchart TD Start([Choose Message Type]) Start --> Q1{Is it a global
announcement?} Q1 -->|Yes
e.g., game paused,
settings changed| Untargeted[ Use UNTARGETED
Everyone listens] Q1 -->|No| Q2{Are you commanding
a specific entity?} Q2 -->|Yes
e.g., heal Player,
open Chest #3| Targeted[ Use TARGETED
One recipient] Q2 -->|No| Q3{Is an entity announcing
something happened?} Q3 -->|Yes
e.g., Enemy died,
Chest opened| Broadcast[ Use BROADCAST
Anyone can observe] Q3 -->|No| Rethink[Rethink your
message design] classDef primary stroke-width:3px class Untargeted primary classDef warning stroke-width:3px class Targeted warning classDef success stroke-width:3px class Broadcast success classDef danger stroke-width:2px class Rethink danger classDef neutral stroke-width:2px class Start,Q1,Q2,Q3 neutral ``` ## Untargeted Messages - Use for cross-cutting notifications: settings changed, scene loaded, world regenerated. - Any listener can subscribe; no specific sender/recipient required. - Define as immutable structs; prefer generic interface for zero-boxing. ```csharp using DxMessaging.Core.Messages; using DxMessaging.Core.Attributes; using DxMessaging.Core.Extensions; [DxUntargetedMessage] [DxAutoConstructor] public readonly partial struct SceneLoaded { public readonly int buildIndex; } // Emit (bind struct to a variable) var sceneLoaded = new SceneLoaded(UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex); sceneLoaded.Emit(); ``` ## Targeted Messages - Use for commands/events directed at one entity: Heal, EquipWeapon, OpenDoor. - You address a specific `InstanceId` (e.g., a player GameObject/component). - Ideal when only one recipient should act. ```csharp using DxMessaging.Core.Messages; using DxMessaging.Core.Attributes; using DxMessaging.Core.Extensions; using UnityEngine; [DxTargetedMessage] [DxAutoConstructor] public readonly partial struct Heal { public readonly int amount; } // Emit to one target (GameObject) var heal = new Heal(10); heal.EmitGameObjectTargeted(playerGameObject); ``` ## Broadcast Messages - Use for reactionary "facts" about a specific source: TookDamage, PickedUpItem. - Many systems can observe and react independently. - Distinct from targeted: the source is the sender; listeners decide if they care. ```csharp using DxMessaging.Core.Messages; using DxMessaging.Core.Attributes; using DxMessaging.Core.Extensions; using UnityEngine; [DxBroadcastMessage] [DxAutoConstructor] public readonly partial struct TookDamage { public readonly int amount; } // Emit from a source (GameObject) var hit = new TookDamage(5); hit.EmitGameObjectBroadcast(enemyGameObject); ``` ## Organizing Messages with Nested Types Group related messages inside a container class for better organization: ```csharp using DxMessaging.Core.Attributes; public partial class CombatEvents { [DxTargetedMessage] [DxAutoConstructor] public readonly partial struct Heal { public readonly int amount; [DxOptionalParameter(false)] // Custom default value public readonly bool showEffect; } [DxBroadcastMessage] [DxAutoConstructor] public readonly partial struct TookDamage { public readonly int amount; [DxOptionalParameter(Expression = "DamageType.Physical")] // Enum default public readonly DamageType type; } } // Usage: var heal = new CombatEvents.Heal(10, showEffect: true); heal.EmitComponentTargeted(player); var damage = new CombatEvents.TookDamage(5); // Uses DamageType.Physical damage.EmitGameObjectBroadcast(enemy); ``` ### Benefits - Reduces namespace pollution - Makes message relationships clear - Works with all message types (Untargeted, Targeted, Broadcast) - Full source generator support ## Listening to everything in a category - All targeted of a type (any target): `RegisterTargetedWithoutTargeting` or post-process with `RegisterTargetedWithoutTargetingPostProcessor`. - All broadcast of a type (any source): `RegisterBroadcastWithoutSource` or post-process with `RegisterBroadcastWithoutSourcePostProcessor`. ```csharp using DxMessaging.Core; using DxMessaging.Core.Messages; // Observe every Heal regardless of target _ = token.RegisterTargetedWithoutTargeting(OnAnyHeal); void OnAnyHeal(ref InstanceId target, ref Heal m) => Audit(target, m); // Observe every TookDamage regardless of source _ = token.RegisterBroadcastWithoutSource(OnAnyTookDamage); void OnAnyTookDamage(ref InstanceId source, ref TookDamage m) => Track(source, m); ``` ## Choosing the right type - Start with Broadcast for "X happened at Y" facts others may observe. - Use Targeted when one specific recipient must act. - Use Untargeted for global state changes anyone might care about. ## Do's - Keep messages small, immutable, and specific. - Use attributes + `DxAutoConstructor` for clarity and onboarding. - Use GameObject/Component helpers (`EmitGameObject*`/`EmitComponent*`) instead of manual `InstanceId` casts. - Organize related messages using nested types for better structure. - Use internal visibility for implementation-only messages. ## Don'ts - Don't use Untargeted for per-entity commands; prefer Targeted. - Don't overload Broadcast for commands; commands need a recipient (Targeted). - Avoid deep inheritance trees; messages should be small, flat data. - Don't emit from temporaries; bind structs to a variable before `Emit*`. --- ## Related Documentation ### Prerequisites - to [Getting Started](../getting-started/getting-started.md) -- Understand the basics first - to [Visual Guide](../getting-started/visual-guide.md) -- See the 3 types visualized #### Next Steps - to [Patterns](../guides/patterns.md) -- Real-world examples of each type - to [Listening Patterns](listening-patterns.md) -- All the ways to receive messages - to [Interceptors & Ordering](interceptors-and-ordering.md) -- Control message flow ##### Try It - to [Quick Start](../getting-started/quick-start.md) -- Working example - to [Mini Combat sample](https://github.com/Ambiguous-Interactive/DxMessaging/blob/master/Samples~/Mini%20Combat/README.md) -- See all 3 types in action