com.wallstop-studios.dxmessaging 2.0.0-rc27.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/Docs/Comparisons.md +194 -66
  2. package/Docs/GettingStarted.md +84 -17
  3. package/Docs/Overview.md +114 -20
  4. package/Docs/Patterns.md +41 -2
  5. package/Docs/Performance.md +9 -9
  6. package/Docs/VisualGuide.md +75 -10
  7. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  8. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +3 -3
  9. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll +0 -0
  10. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +2 -2
  11. package/Editor/Analyzers/System.Collections.Immutable.dll +0 -0
  12. package/Editor/Analyzers/System.Reflection.Metadata.dll +0 -0
  13. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
  14. package/README.md +262 -63
  15. package/Runtime/Core/MessageBus/MessageBus.cs +13 -0
  16. package/Runtime/Core/MessageHandler.cs +27 -33
  17. package/Runtime/Core/MessageRegistrationToken.cs +12 -21
  18. package/Runtime/Unity/MessageAwareComponent.cs +6 -0
  19. package/Runtime/Unity/MessagingComponent.cs +24 -0
  20. package/Samples~/Mini Combat/README.md +81 -21
  21. package/Samples~/Mini Combat/Walkthrough.md +23 -1
  22. package/Samples~/UI Buttons + Inspector/README.md +55 -12
  23. package/Tests/Runtime/Core/MessagingComponentLifecycleTests.cs +89 -0
  24. package/Tests/Runtime/Core/MessagingComponentLifecycleTests.cs.meta +11 -0
  25. package/Tests/Runtime/Core/ReflexiveMessageWarningTests.cs +86 -0
  26. package/Tests/Runtime/Core/ReflexiveMessageWarningTests.cs.meta +11 -0
  27. package/Tests/Runtime/Core/SourceGeneratorNestedTests.cs +1 -1
  28. package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +116 -0
  29. package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs.meta +11 -0
  30. package/Tests/Runtime/Scripts/Components/ReflexiveReceiverComponent.cs +14 -0
  31. package/Tests/Runtime/Scripts/Components/ReflexiveReceiverComponent.cs.meta +11 -0
  32. package/package.json +1 -1
@@ -1,75 +1,127 @@
1
- # Comparisons: Events, Unity Events, and Unity Messages
1
+ # Comparisons: DxMessaging vs. Everything Else
2
2
 
3
- This guide shows common pain points in standard approaches and how DxMessaging addresses them with clearer ownership, ordering, and observability.
3
+ **TL;DR:** If you've used C# events, UnityEvents, or static event buses and thought "there has to be a better way," you're right. DxMessaging fixes the pain points while keeping the benefits.
4
4
 
5
- Table of contents
5
+ ## This guide shows
6
6
 
7
- - C# events/delegates
8
- - UnityEvents (inspector wiring)
9
- - Unity SendMessage
10
- - Global “Event Bus” singletons
11
- - How DxMessaging addresses each
12
- - When to use which
7
+ - What's wrong with each approach (with real code examples)
8
+ - How DxMessaging solves it (with real code examples)
9
+ - Honest trade-offs (what you give up, what you gain)
10
+ - When to actually use each approach (no BS)
13
11
 
14
- Standard C# Events/Actions
12
+ ### Table of Contents
15
13
 
16
- Problems
14
+ - [C# Events/Delegates](#standard-c-eventsactions)
15
+ - [UnityEvents](#unityevents-inspector-wiring)
16
+ - [Unity SendMessage](#unity-sendmessage)
17
+ - [Static Event Buses](#global-event-bus-singletons)
18
+ - [Honest Trade-offs](#honest-trade-offs-what-you-give-up-what-you-gain)
19
+ - [Feature Matrix](#feature-by-feature-comparison-matrix)
20
+ - [Decision Guide](#when-each-approach-actually-wins)
17
21
 
18
- - Manual attach/detach: easy to forget unsubscribe; memory leaks and callbacks on destroyed objects.
19
- - Tight coupling: consumers reference producers (or vice‑versa), hurting modularity and tests.
20
- - Ordering is implicit: hard to coordinate A before B across systems.
21
- - Hard to observe globally: no built‑in way to inspect “what fired recently”.
22
+ ## Standard C# Events/Actions
22
23
 
23
- Typical code
24
+ ### The Pain Points (You've Felt These)
25
+
26
+ #### 1. Memory Leak Hell
24
27
 
25
28
  ```csharp
26
- public sealed class Spawner
27
- {
28
- public event Action Spawned;
29
- public void Spawn()
30
- {
31
- // ...
32
- Spawned?.Invoke();
29
+ public class UI : MonoBehaviour {
30
+ void OnEnable() {
31
+ GameManager.Instance.OnScoreChanged += UpdateScore;
32
+ }
33
+
34
+ void OnDisable() {
35
+ // ❌ Forgot this line? MEMORY LEAK!
36
+ GameManager.Instance.OnScoreChanged -= UpdateScore;
33
37
  }
34
38
  }
39
+ ```
35
40
 
36
- public sealed class UI
37
- {
38
- private readonly Spawner _spawner;
39
- public UI(Spawner spawner)
40
- {
41
- _spawner = spawner;
42
- _spawner.Spawned += OnSpawned; // must remember to unsubscribe
41
+ **Real story:** You forget `OnDisable` once. Six months later: "Why is our mobile game crashing after 30 minutes?"
42
+
43
+ ##### 2. Tight Coupling Nightmare
44
+
45
+ ```csharp
46
+ public class Spawner {
47
+ public event Action Spawned;
48
+ public void Spawn() => Spawned?.Invoke();
49
+ }
50
+
51
+ public class UI {
52
+ // ❌ UI now depends on Spawner directly
53
+ [SerializeField] private Spawner spawner;
54
+
55
+ void Awake() {
56
+ spawner.Spawned += OnSpawned; // Tight coupling
43
57
  }
44
- private void OnSpawned() => Refresh();
45
58
  }
46
59
  ```
47
60
 
48
- DxMessaging
61
+ **Problem:** Want to add a second spawner? Refactor Spawner? Hope you like breaking things.
49
62
 
50
- - No direct coupling; the UI listens for a message instead of referencing a specific Spawner instance.
51
- - Lifecycle managed by a token; enable/disable tied to a component.
52
- - Ordering via priority; global inspection via diagnostics and the custom inspector.
63
+ ###### 3. Mystery Execution Order
53
64
 
54
65
  ```csharp
55
- using DxMessaging.Core.Attributes;
56
- using DxMessaging.Core.Extensions;
57
- using DxMessaging.Core.Messages;
66
+ // Which runs first? 🤷
67
+ AudioSystem.OnGameEnd += FadeMusic;
68
+ SaveSystem.OnGameEnd += SaveGame;
69
+ UISystem.OnGameEnd += ShowCredits;
70
+ ```
58
71
 
59
- [DxUntargetedMessage]
60
- [DxAutoConstructor]
61
- public readonly partial struct Spawned { }
72
+ **Result:** Sometimes SaveGame runs after UISystem shows credits. Flaky bugs that only happen sometimes.
62
73
 
63
- // Producer
64
- var evt = new Spawned();
65
- evt.Emit();
74
+ ###### 4. Debugging Black Hole
75
+
76
+ "Which event fired when? Who's subscribed?" → Set 50 breakpoints and hope.
77
+
78
+ ### The DxMessaging Way
79
+
80
+ #### 1. Impossible to Leak
81
+
82
+ ```csharp
83
+ public class UI : MessageAwareComponent {
84
+ protected override void RegisterMessageHandlers() {
85
+ base.RegisterMessageHandlers();
86
+ _ = Token.RegisterUntargeted<ScoreChanged>(UpdateScore);
87
+ }
88
+ // ✅ That's it! Automatic cleanup when destroyed.
89
+ }
90
+ ```
91
+
92
+ ##### 2. Zero Coupling
93
+
94
+ ```csharp
95
+ // Spawner doesn't know about UI
96
+ public class Spawner : MonoBehaviour {
97
+ void Spawn() {
98
+ // Just emit, don't care who's listening
99
+ new SpawnedEnemy().Emit();
100
+ }
101
+ }
66
102
 
67
- // Consumer (Unity)
68
- _ = token.RegisterUntargeted<Spawned>(OnSpawned);
69
- void OnSpawned(ref Spawned m) => Refresh();
103
+ // UI doesn't know about Spawner
104
+ public class UI : MessageAwareComponent {
105
+ protected override void RegisterMessageHandlers() {
106
+ _ = Token.RegisterUntargeted<SpawnedEnemy>(OnSpawn);
107
+ }
108
+ }
70
109
  ```
71
110
 
72
- UnityEvents (inspector wiring)
111
+ ###### 3. Explicit Execution Order
112
+
113
+ ```csharp
114
+ // Clear, documented order
115
+ AudioSystem: priority: 10 // Runs third
116
+ SaveSystem: priority: 0 // Runs first
117
+ UISystem: priority: 5 // Runs second
118
+ ```
119
+
120
+ ###### 4. Built-in Debugging
121
+
122
+ Open any component in Inspector → See message history with timestamps. Done.
123
+
124
+ ## UnityEvents (Inspector Wiring)
73
125
 
74
126
  Problems
75
127
 
@@ -99,7 +151,7 @@ DxMessaging
99
151
  - Strongly‑typed registrations in code; explicit priorities and stages.
100
152
  - Inspect and page through emissions/registrations from MessagingComponent inspector.
101
153
 
102
- Unity SendMessage
154
+ ## Unity SendMessage
103
155
 
104
156
  Problems
105
157
 
@@ -120,7 +172,7 @@ var msg = new ReflexiveMessage("OnHit", ReflexiveSendMode.Upwards, 10);
120
172
  MessageHandler.MessageBus.TargetedBroadcast(ref target, ref msg);
121
173
  ```
122
174
 
123
- Global Event Bus singletons
175
+ ## Global Event Bus Singletons
124
176
 
125
177
  Problems
126
178
 
@@ -183,23 +235,36 @@ When to use which
183
235
 
184
236
  ## Honest Trade-offs: What You Give Up, What You Gain
185
237
 
186
- No solution is perfect. Here's what you sacrifice and gain with DxMessaging compared to alternatives.
238
+ **Let's be real:** DxMessaging isn't free magic. You trade some things for others. Here's the unfiltered truth about what you gain and what you sacrifice.
239
+
240
+ **Bottom line first:** For game jam prototypes, C# events are faster to write. For anything you'll maintain for months, DxMessaging saves you time and sanity.
187
241
 
188
242
  ### Learning Curve
189
243
 
190
244
  #### What You Give Up
191
245
 
192
- - ❌ Immediate productivity - There's a 1-2 day learning curve
193
- - ❌ Familiarity - Team needs to understand message types, tokens, and lifecycle
194
- - ❌ "Just works" - Requires upfront design (which message type? what priority?)
246
+ - ❌ **Immediate productivity** - ~1-2 days to feel comfortable (reading docs, trying examples)
247
+ - ❌ **Familiarity** - Your team knows C# events already; DxMessaging is new
248
+ - ❌ **"Just works" intuition** - You need to think: "Which message type? What priority?"
249
+
250
+ **Real talk:** Your first message will take 15 minutes. By the 10th message, you'll be faster than with events.
195
251
 
196
252
  #### What You Gain
197
253
 
198
- - ✅ Long-term velocity - Once learned, adding features is faster
199
- - ✅ Reduced debugging time - Clear message flow, Inspector diagnostics
200
- - ✅ Onboarding clarity - New devs see explicit message contracts instead of hidden event chains
254
+ - ✅ **Long-term velocity** - Adding new features doesn't require touching 5 existing systems
255
+ - ✅ **Debugging is 10x faster** - Inspector shows "what fired when" instantly
256
+ - ✅ **Onboarding is easier** - New devs see explicit message contracts, not hidden event chains
257
+
258
+ **Example:** Junior dev asks "How does damage work?"
259
+
260
+ - **C# events:** "Uh, Player has an OnDamaged event, and HealthBar subscribes in line 47, and..."
261
+ - **DxMessaging:** "Search for `TookDamage` message, see who emits it and who listens."
201
262
 
202
- **Verdict:** If you're building a game jam prototype, the learning curve isn't worth it. For multi-month projects, it pays off quickly.
263
+ ##### Verdict
264
+
265
+ - Game jam (1 week project): Learning curve not worth it → Stick with C# events
266
+ - Mid-size game (1+ month): Pays off by week 2
267
+ - Large game (6+ months): Essential for sanity
203
268
 
204
269
  ### Boilerplate
205
270
 
@@ -449,17 +514,80 @@ public void TestAchievementSystem() {
449
514
 
450
515
  **Break-even point:** Usually around 10-20 hours into a project, when event management becomes painful.
451
516
 
452
- ## Making the Decision
517
+ ## Making the Decision (Be Honest With Yourself)
518
+
519
+ ### Answer these questions honestly
520
+
521
+ ### 1. Project Lifespan?
522
+
523
+ - **<1 week (game jam):** Skip DxMessaging → Use C# events or direct calls
524
+ - **1-4 weeks (prototype):** Maybe → If you plan to continue, use DxMessaging
525
+ - **1+ months (real project):** Yes → DxMessaging will save you time
526
+ - **6+ months (production):** Absolutely → You'll thank yourself later
527
+
528
+ ### 2. Team Size?
529
+
530
+ - **Solo dev:** Optional → Depends on project complexity
531
+ - **2-3 devs:** Valuable → Reduces communication overhead
532
+ - **4+ devs:** Highly recommended → Clear contracts between systems
533
+ - **Remote/distributed team:** Essential → Explicit message contracts prevent miscommunication
534
+
535
+ ### 3. Codebase Size?
536
+
537
+ - **<1k lines:** Skip it → Direct method calls are fine
538
+ - **1k-5k lines:** Consider it → If you're growing fast
539
+ - **5k-20k lines:** Recommended → Coupling becomes painful
540
+ - **20k+ lines:** Absolutely → Refactoring without it is a nightmare
541
+
542
+ ### 4. How Many Systems Need to Communicate?
543
+
544
+ - **1-2 systems:** Skip → Just call methods directly
545
+ - **3-5 systems:** Consider → If they don't share references
546
+ - **6-10 systems:** Recommended → Coupling becomes unmanageable
547
+ - **10+ systems:** Essential → You're drowning in SerializeFields
548
+
549
+ ### 5. Have You Had Memory Leaks From Forgotten Unsubscribes?
550
+
551
+ - **Never:** Lucky you! Optional
552
+ - **Once or twice:** Consider it → Prevention is cheaper than debugging
553
+ - **Multiple times:** Absolutely → Stop wasting time on this
554
+ - **Currently debugging one:** Drop everything and adopt DxMessaging now
555
+
556
+ ### 6. How Often Do You Debug "What Fired When?"
557
+
558
+ - **Never:** You're either lying or working on tiny projects
559
+ - **Rarely:** Optional, but would help
560
+ - **Monthly:** Recommended → Inspector diagnostics will save hours
561
+ - **Weekly:** Absolutely → You're wasting too much time
562
+
563
+ ### Quick Decision Matrix
564
+
565
+ ```text
566
+ Game Jam → C# Events (speed over safety)
567
+ Prototype → DxMessaging IF continuing, else C# Events
568
+ Production → DxMessaging (unless <1k lines)
569
+ Legacy codebase → Migrate gradually (see Migration Guide)
570
+ ```
571
+
572
+ ### The Real Question
573
+
574
+ #### "Will this project still exist in 3 months?"
575
+
576
+ - **No:** C# events are fine
577
+ - **Yes:** Use DxMessaging
578
+
579
+ ##### "Will anyone else work on this code?"
580
+
581
+ - **No:** C# events might be okay
582
+ - **Yes:** Use DxMessaging (future you counts as "someone else")
453
583
 
454
- Ask yourself:
584
+ ### Rule of Thumb
455
585
 
456
- 1. **Project lifespan?** <1 week → Skip DxMessaging | >1 month → Consider it
457
- 1. **Team size?** Solo → Optional | 3+ devs → Highly valuable
458
- 1. **Codebase size?** <5k lines → Optional | >10k lines → Recommended
459
- 1. **Event complexity?** <10 events → Skip | >20 events → Use DxMessaging
460
- 1. **Memory leak history?** None → Optional | Frequent → MUST HAVE
586
+ If you're reading this and thinking:
461
587
 
462
- **Rule of thumb:** If you're reading this and thinking "I've experienced these pain points," DxMessaging will help. If you're thinking "I've never had these problems," maybe you don't need it yet.
588
+ - **"I've experienced these pain points"** DxMessaging will help
589
+ - **"This seems like overkill"** → You probably don't need it yet
590
+ - **"I need this yesterday"** → Welcome home 🚀
463
591
 
464
592
  See also
465
593
 
@@ -27,13 +27,31 @@ By the end of this guide, you will:
27
27
 
28
28
  ## What is DxMessaging?
29
29
 
30
- DxMessaging is a high‑performance, type‑safe messaging system for Unity. It replaces sprawling C# events, brittle UnityEvents, and ad‑hoc global buses with clean, observable, and predictable communication.
30
+ **Picture this:** You're building a Unity game. Your player takes damage. Now you need to:
31
31
 
32
- Think of it as the event system you wish Unity had built‑in:
32
+ - Update the health bar UI
33
+ - Play a damage sound
34
+ - Show a damage number popup
35
+ - Track damage for analytics
36
+ - Check if an achievement unlocked
37
+ - Maybe trigger a tutorial tip
33
38
 
34
- - Decoupled systems without manual subscribe/unsubscribe headaches
35
- - Predictable execution order with powerful interception and diagnostics
36
- - Scales from prototypes to large production codebases
39
+ **The old way:** The Player script needs references to all 6 systems. Or they all need references to the Player. It's a tangled mess.
40
+
41
+ **The DxMessaging way:** The Player emits one message: `TookDamage(25)`. Everyone who cares receives it automatically. Zero coupling, zero leaks, zero hassle.
42
+
43
+ ---
44
+
45
+ **Technical summary:** DxMessaging is a high-performance, type-safe messaging system that replaces C# events, UnityEvents, and global event buses with a clean, observable, and predictable communication pattern.
46
+
47
+ **Think of it as:** The event system Unity should have shipped with.
48
+
49
+ ### What you get
50
+
51
+ - **Decoupled systems** - no manual subscribe/unsubscribe, impossible to leak
52
+ - **Predictable execution** - priority-based ordering, see exactly what runs when
53
+ - **Actually debuggable** - Inspector shows message history with timestamps
54
+ - **Scales effortlessly** - works for prototypes and 100k+ line codebases
37
55
 
38
56
  ## Quick Start
39
57
 
@@ -91,27 +109,76 @@ heal.EmitGameObjectTargeted(playerGameObject);
91
109
 
92
110
  ## Message Types
93
111
 
94
- - Untargeted: fire‑and‑forget announcements (no specific receiver)
95
- - Targeted: deliver to a specific receiver (GameObject, InstanceId, etc.)
96
- - Broadcast: deliver to all listeners (optionally including source metadata)
112
+ ### New to messaging? Use this decision tree
113
+
114
+ ```text
115
+ Is it a global announcement? (pause, settings, scene load)
116
+ → Use UNTARGETED
117
+
118
+ Are you commanding a specific entity? (heal Player, open Chest #3)
119
+ → Use TARGETED
120
+
121
+ Is an entity announcing something happened? (Enemy died, Chest opened)
122
+ → Use BROADCAST
123
+ ```
124
+
125
+ #### Examples
126
+
127
+ ```csharp
128
+ // Untargeted: "Everyone, the game paused!"
129
+ [DxUntargetedMessage]
130
+ public struct GamePaused { }
131
+
132
+ // Targeted: "Player, heal yourself by 50!"
133
+ [DxTargetedMessage]
134
+ public struct Heal { public int amount; }
97
135
 
98
- See [MessageTypes](MessageTypes.md) for details and APIs.
136
+ // Broadcast: "I (Enemy #3) just died!"
137
+ [DxBroadcastMessage]
138
+ public struct EnemyDied { public string enemyName; }
139
+ ```
140
+
141
+ **Still confused?** See the [Visual Guide](VisualGuide.md) for beginner-friendly explanations, or [MessageTypes](MessageTypes.md) for technical details.
99
142
 
100
143
  ## Common Patterns
101
144
 
102
- - UI reacting to gameplay state via targeted messages
103
- - Cross‑system notifications using broadcast messages
104
- - Configuration changes/feature toggles via untargeted announcements
145
+ ### Want to see real examples? Here's what DxMessaging excels at
146
+
147
+ - **UI reacting to gameplay** - Health bar updates when player takes damage (without UI knowing about Player)
148
+ - **Achievement systems** - Track ALL kills across ALL enemies with ONE listener
149
+ - **Cross-system coordination** - Scene transitions coordinate audio, save system, and UI automatically
150
+ - **Input handling** - Decouple input system from player controller
151
+ - **Analytics** - Track all events without polluting gameplay code
105
152
 
106
- See [ListeningPatterns](ListeningPatterns.md) and [Patterns](Patterns.md) for deeper examples.
153
+ **Want code examples?** See [Patterns](Patterns.md) for production-ready patterns and [ListeningPatterns](ListeningPatterns.md) for advanced techniques.
107
154
 
108
155
  ## Troubleshooting
109
156
 
110
- - Nothing happens? Ensure your listener registered in `RegisterMessageHandlers` and the component is enabled.
111
- - Duplicate behavior? Check for multiple registrations or missing token disposal on custom lifecycles.
112
- - Ordering issues? Use interceptors/post‑processors to control/inspect flow.
157
+ ### "My handler isn't being called!"
158
+
159
+ Checklist:
160
+
161
+ 1. Did you call `base.RegisterMessageHandlers()` first?
162
+ 1. Is your component enabled in the scene?
163
+ 1. Are you emitting to the right target? (Check GameObject vs Component)
164
+ 1. Check the Inspector - does the registration show up?
165
+
166
+ #### "My message is firing twice!"
167
+
168
+ - Check if you accidentally registered the same handler multiple times
169
+ - Make sure you're calling `base.RegisterMessageHandlers()` only once
170
+
171
+ ##### "I get a compile error on `[DxAutoConstructor]`"
172
+
173
+ - Did you mark the struct as `partial`? (required for code generation)
174
+ - Example: `public readonly partial struct MyMessage`
175
+
176
+ ###### "Which message type should I use?"
177
+
178
+ - See the decision tree in [Message Types](#message-types) above
179
+ - When in doubt, start with `Broadcast` - it's the most flexible
113
180
 
114
- See [Troubleshooting](Troubleshooting.md) for more.
181
+ **Still stuck?** See [Troubleshooting](Troubleshooting.md) for the complete guide or [FAQ](FAQ.md) for common questions.
115
182
 
116
183
  ## Next Steps
117
184
 
package/Docs/Overview.md CHANGED
@@ -4,22 +4,89 @@
4
4
 
5
5
  ---
6
6
 
7
- DxMessaging is a highperformance, typesafe messaging system for Unity and .NET that decouples producers and consumers without sprawling events or brittle global hooks. It gives you clear message categories, predictable ordering, and tooling to observe, intercept, and diagnose message flows.
7
+ DxMessaging is a high-performance, type-safe messaging system for Unity that **eliminates the three biggest pain points** of traditional event systems:
8
8
 
9
- What it solves
9
+ 1. **Memory leaks** from forgotten unsubscribes → Automatic lifecycle management
10
+ 1. **Tight coupling** creating refactoring nightmares → Full decoupling with no direct references
11
+ 1. **Debugging black holes** ("what fired when?") → Built-in Inspector diagnostics
10
12
 
11
- - Decoupling without tight references: producers don’t need to know consumers.
12
- - Predictable lifecycle: explicit registration tokens that you enable/disable with Unity components.
13
- - Ergonomics and performance: struct‑friendly APIs, by‑ref handlers, zero‑boxing patterns.
14
- - Observability: interceptors, post‑processors, diagnostics buffers, and registration logs.
15
- - Scalable message taxonomy: Untargeted, Targeted, and Broadcast messages fit most gameplay/UI flows.
13
+ ## What Problems Does It Solve?
16
14
 
17
- When to consider DxMessaging
15
+ ### For Beginners: "I'm calling methods manually everywhere"
18
16
 
19
- - You’re fighting complex webs of C# events/delegates with manual attach/detach and order issues.
20
- - You need to decouple systems that span scenes or don’t share direct references.
21
- - You want to model Gameplay/UI flows as messages with clear ownership (global vs to one entity vs from one entity).
22
- - You need to inspect, validate, and sometimes cancel or normalize emissions.
17
+ #### Your code probably looks like this
18
+
19
+ ```csharp
20
+ public class Player : MonoBehaviour {
21
+ public HealthBar healthBar;
22
+ public AudioManager audio;
23
+ public AchievementSystem achievements;
24
+
25
+ void TakeDamage(int amount) {
26
+ health -= amount;
27
+ healthBar.UpdateHealth(health); // Manual call
28
+ audio.PlayDamageSound(); // Manual call
29
+ achievements.CheckDamage(amount); // Manual call
30
+ // Add analytics? More manual calls...
31
+ }
32
+ }
33
+ ```
34
+
35
+ **Every new system = another SerializeField + another manual call.** It's exhausting and brittle.
36
+
37
+ ##### DxMessaging fixes this
38
+
39
+ ```csharp
40
+ void TakeDamage(int amount) {
41
+ health -= amount;
42
+ new TookDamage(amount).EmitComponentBroadcast(this);
43
+ // Done! Everything else reacts automatically.
44
+ }
45
+ ```
46
+
47
+ ### For Intermediate Devs: "I use C# events but they leak"
48
+
49
+ #### You know this pain
50
+
51
+ ```csharp
52
+ void OnEnable() { GameManager.OnScoreChanged += UpdateUI; }
53
+ void OnDisable() { /* Forgot this? 💀 LEAK! */ }
54
+ ```
55
+
56
+ **DxMessaging makes leaks impossible** - automatic cleanup when components die.
57
+
58
+ ### For Advanced Devs: "I need observability and control"
59
+
60
+ - ✅ See message history in Inspector (timestamps, payloads, call counts)
61
+ - ✅ Priority-based execution (no more race conditions)
62
+ - ✅ Interceptors (validate/normalize before handlers)
63
+ - ✅ Global observers (track ALL instances of a message type)
64
+ - ✅ Local bus islands (isolated testing, zero global state)
65
+
66
+ ## What It Solves (Technical)
67
+
68
+ - **Decoupling without references** - producers/consumers never know about each other
69
+ - **Predictable lifecycle** - explicit tokens tied to Unity component lifecycles
70
+ - **Performance** - struct messages passed by-ref, zero allocations, zero boxing
71
+ - **Observability** - interceptors, post-processors, diagnostics, registration logs
72
+ - **Scalable taxonomy** - three message types (Untargeted/Targeted/Broadcast) cover 99% of use cases
73
+
74
+ ## When to Consider DxMessaging
75
+
76
+ ### Use it when
77
+
78
+ - You have 3+ systems that need to communicate
79
+ - You've debugged memory leaks from forgotten unsubscribes
80
+ - You're tired of UI depending on 15 different gameplay systems
81
+ - You want to see "what fired when" without setting 50 breakpoints
82
+ - You're building for the long term (months/years, not days)
83
+
84
+ #### Skip it when
85
+
86
+ - Game jam prototype (<1 week)
87
+ - Tiny project (<1000 lines)
88
+ - Single-system communication (just call the method directly)
89
+ - You need synchronous return values (DxMessaging is fire-and-forget)
23
90
 
24
91
  Core ideas
25
92
 
@@ -31,15 +98,42 @@ Core ideas
31
98
  - Pipeline: Interceptors → Handlers → Post‑Processors, with diagnostics optionally enabled.
32
99
  - Unity integration: `MessagingComponent` and `MessageAwareComponent` manage lifecycles cleanly.
33
100
 
34
- Killer features
101
+ ## Killer Features (What Makes It Special)
102
+
103
+ ### 🚀 Global Observers: The Unique Advantage
104
+
105
+ #### Traditional event systems force you to do this
106
+
107
+ ```csharp
108
+ // Subscribe to each entity type separately
109
+ PlayerEvents.OnDamaged += TrackPlayerDamage;
110
+ EnemyEvents.OnDamaged += TrackEnemyDamage;
111
+ NPCEvents.OnDamaged += TrackNPCDamage;
112
+ // Add a new entity type? More subscriptions...
113
+ ```
114
+
115
+ ##### DxMessaging lets you do this
116
+
117
+ ```csharp
118
+ // Subscribe ONCE to ALL damage, regardless of source
119
+ _ = Token.RegisterBroadcastWithoutSource<TookDamage>(
120
+ (InstanceId source, TookDamage msg) => {
121
+ Analytics.Log($"{source} took {msg.amount} damage");
122
+ }
123
+ );
124
+ ```
125
+
126
+ **Real-world impact:** Build achievement systems, combat logs, and analytics that work with ANY entity - even ones that don't exist yet.
127
+
128
+ ### Other Killer Features
35
129
 
36
- - **🚀 Global Observers: Listen to ALL messages** — Subscribe to all targeted/broadcast messages of a type without knowing specific targets/sources. **Unlike traditional event buses** where you need separate subscriptions per entity type (PlayerDamaged, EnemyDamaged, etc.), DxMessaging lets you subscribe ONCE to ALL damage events and get the source/target as a parameter. Perfect for analytics, debugging, achievements, and combat logs.
37
- - **Priority ordering** and explicit pipeline stages (interceptors, handlers, post‑processors).
38
- - **Local bus islands** for test isolation and modular subsystems.
39
- - **Struct‑friendly, byref handlers** to avoid boxing and copies.
40
- - **Attributes + source generation** (`DxAutoConstructor`) reduce boilerplate while keeping strong typing.
41
- - **Unityfirst helpers** (GameObject/Component emit) and a powerful MessagingComponent inspector.
42
- - **Global accept‑all** for building inspectors and profilers.
130
+ - **Priority-based ordering** - eliminate race conditions, control execution flow explicitly
131
+ - **Interceptor pipeline** - validate/normalize messages BEFORE handlers run (one validation, all handlers protected)
132
+ - **Local bus islands** - isolated testing with zero global state contamination
133
+ - **Zero-allocation design** - struct messages passed by-ref, no boxing, no GC spikes
134
+ - **Auto-constructor generation** - `[DxAutoConstructor]` eliminates boilerplate while keeping type safety
135
+ - **Unity-first helpers** - `EmitGameObjectTargeted()`, `EmitComponentBroadcast()` feel natural
136
+ - **Inspector diagnostics** - see message history, registrations, call counts in real-time
43
137
 
44
138
  ---
45
139
 
package/Docs/Patterns.md CHANGED
@@ -1,10 +1,49 @@
1
- # DxMessaging Patterns
1
+ # DxMessaging Patterns: Real-World Solutions
2
2
 
3
3
  [← Back to Index](Index.md) | [Getting Started](GettingStarted.md) | [Message Types](MessageTypes.md) | [Samples](../Samples~/)
4
4
 
5
5
  ---
6
6
 
7
- This document captures practical patterns for building systems with DxMessaging. It complements the README by focusing on composition, structure, and problem-solving techniques.
7
+ **You're here because:** You understand DxMessaging basics, now you want to see "How do I actually build X?"
8
+
9
+ ## What you'll find
10
+
11
+ - **Basic Patterns** - Fundamental building blocks (scene transitions, commands, observability)
12
+ - **Advanced Patterns** - Power user techniques (diagnostics, testing, legacy integration)
13
+ - **Scale Patterns** - Production-ready examples (100+ entities, cross-scene systems, large UI)
14
+
15
+ ### Reading guide
16
+
17
+ - **New to DxMessaging?** Start with Basic Patterns 1-8
18
+ - **Intermediate user?** Jump to Advanced Patterns 9-12
19
+ - **Building at scale?** Go straight to Real-World Scale Patterns
20
+ - **Specific problem?** Use Ctrl+F / Cmd+F to search
21
+
22
+ **Philosophy:** These aren't toy examples. They're patterns from real games with real problems.
23
+
24
+ ---
25
+
26
+ ## Quick Links: "I Want To..."
27
+
28
+ ### Find your use case, jump to the pattern
29
+
30
+ | I want to... | Go to |
31
+ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
32
+ | Make UI react to gameplay | [Pattern 2: Directed Commands](#2-directed-commands-targeted) |
33
+ | Coordinate scene transitions | [Pattern 1: Scene-wide Events](#1-scene-wide-events-untargeted) |
34
+ | Build an achievement system | [Pattern 3: Observability](#3-observability-broadcast) + [Global Accept-All](#10-global-accept-all-handlers) |
35
+ | Validate input/damage before it happens | [Pattern 4: Interceptors](#4-validation-and-normalization-interceptors) |
36
+ | Add analytics without touching gameplay | [Pattern 5: Post-Processors](#5-analyticslogging-post-processors) |
37
+ | Track ALL damage from ANY entity | [Pattern: Managing 100+ Entities](#pattern-managing-100-combat-entities) |
38
+ | Build a large UI system (20+ panels) | [Pattern: Large-Scale UI](#pattern-large-scale-ui-system-20-panels) |
39
+ | Make systems run in a specific order | [Pattern: Priority Ordering](#pattern-priority-ordered-execution-for-complex-systems) |
40
+ | Test in isolation | [Pattern 6: Local Bus Islands](#6-local-bus-islands) |
41
+ | Migrate from C# events | [Pattern 9: Bridging Legacy](#9-bridging-legacy-unity-messaging) |
42
+ | Handle persistent systems across scene loads | [Pattern: Cross-Scene Persistent](#pattern-cross-scene-persistent-systems) |
43
+ | See what's happening (debug message flow) | [Pattern 11: Diagnostics](#11-diagnostics-and-tuning) |
44
+ | Build a battle royale / large multiplayer | [Pattern: Battle Royale Example](#real-world-production-example-battle-royale-game) |
45
+
46
+ ---
8
47
 
9
48
  ## Table of Contents
10
49