com.wallstop-studios.dxmessaging 2.0.0-rc27.3.1 β†’ 2.1.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 (185) hide show
  1. package/.github/workflows/format-on-demand.yml +2 -2
  2. package/.github/workflows/json-format-check.yml +1 -1
  3. package/.github/workflows/markdown-json.yml +1 -1
  4. package/.github/workflows/markdownlint.yml +1 -1
  5. package/.github/workflows/npm-publish.yml +1 -1
  6. package/.github/workflows/prettier-autofix.yml +2 -2
  7. package/.github/workflows/yaml-format-lint.yml +1 -1
  8. package/Docs/Advanced.md +26 -1
  9. package/Docs/Comparisons.md +1352 -141
  10. package/Docs/Compatibility.md +27 -0
  11. package/Docs/DesignAndArchitecture.md +41 -34
  12. package/Docs/EmitShorthands.md +34 -0
  13. package/Docs/GettingStarted.md +84 -17
  14. package/Docs/Helpers.md +1 -1
  15. package/Docs/Index.md +28 -25
  16. package/Docs/Install.md +29 -6
  17. package/Docs/Integrations/Reflex.md +292 -0
  18. package/Docs/Integrations/Reflex.md.meta +7 -0
  19. package/Docs/Integrations/VContainer.md +324 -0
  20. package/Docs/Integrations/VContainer.md.meta +7 -0
  21. package/Docs/Integrations/Zenject.md +333 -0
  22. package/Docs/Integrations/Zenject.md.meta +7 -0
  23. package/{Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.pdb.meta β†’ Docs/Integrations.meta} +2 -1
  24. package/Docs/InterceptorsAndOrdering.md +371 -17
  25. package/Docs/ListeningPatterns.md +206 -0
  26. package/Docs/MessageBusProviders.md +496 -0
  27. package/Docs/MessageBusProviders.md.meta +7 -0
  28. package/Docs/MessageTypes.md +27 -0
  29. package/Docs/MigrationGuide.md +45 -0
  30. package/Docs/Overview.md +114 -20
  31. package/Docs/Patterns.md +327 -2
  32. package/Docs/Performance.md +9 -9
  33. package/Docs/QuickReference.md +31 -0
  34. package/Docs/RuntimeConfiguration.md +407 -0
  35. package/Docs/RuntimeConfiguration.md.meta +7 -0
  36. package/Docs/UnityIntegration.md +3 -1
  37. package/Docs/VisualGuide.md +281 -167
  38. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  39. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +3 -3
  40. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll +0 -0
  41. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +2 -2
  42. package/Editor/Analyzers/System.Collections.Immutable.dll +0 -0
  43. package/Editor/Analyzers/System.Reflection.Metadata.dll +0 -0
  44. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
  45. package/Editor/CustomEditors/MessagingComponentEditor.cs +15 -6
  46. package/README.md +388 -67
  47. package/Runtime/AssemblyInfo.cs +4 -0
  48. package/Runtime/Core/Extensions/MessageBusExtensions.cs +253 -0
  49. package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -0
  50. package/Runtime/Core/Extensions/MessageExtensions.cs +137 -89
  51. package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs +23 -0
  52. package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -0
  53. package/Runtime/Core/MessageBus/IMessageBusProvider.cs +14 -0
  54. package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -0
  55. package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +18 -0
  56. package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -0
  57. package/Runtime/Core/MessageBus/MessageBusRebindMode.cs +26 -0
  58. package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -0
  59. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +383 -0
  60. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -0
  61. package/Runtime/Core/MessageHandler.cs +198 -27
  62. package/Runtime/Core/MessageRegistrationToken.cs +67 -25
  63. package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs +31 -0
  64. package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +12 -0
  65. package/Runtime/Unity/InitialGlobalMessageBusProvider.cs +38 -0
  66. package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +12 -0
  67. package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs +11 -0
  68. package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +3 -0
  69. package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +73 -0
  70. package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +11 -0
  71. package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef +20 -0
  72. package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef.meta +7 -0
  73. package/Runtime/Unity/Integrations/Reflex.meta +8 -0
  74. package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs +11 -0
  75. package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +3 -0
  76. package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +46 -0
  77. package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +11 -0
  78. package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef +30 -0
  79. package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef.meta +7 -0
  80. package/Runtime/Unity/Integrations/VContainer.meta +8 -0
  81. package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs +11 -0
  82. package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +3 -0
  83. package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef +30 -0
  84. package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef.meta +7 -0
  85. package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +55 -0
  86. package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +11 -0
  87. package/Runtime/Unity/Integrations/Zenject.meta +8 -0
  88. package/Runtime/Unity/Integrations.meta +8 -0
  89. package/Runtime/Unity/MessageAwareComponent.cs +102 -0
  90. package/Runtime/Unity/MessageBusProviderHandle.cs +97 -0
  91. package/Runtime/Unity/MessageBusProviderHandle.cs.meta +12 -0
  92. package/Runtime/Unity/MessagingComponent.cs +164 -2
  93. package/Runtime/Unity/MessagingComponentInstaller.cs +120 -0
  94. package/Runtime/Unity/MessagingComponentInstaller.cs.meta +12 -0
  95. package/Runtime/Unity/ScriptableMessageBusProvider.cs +14 -0
  96. package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +12 -0
  97. package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab +98 -0
  98. package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab.meta +7 -0
  99. package/Samples~/DI/Prefabs.meta +8 -0
  100. package/Samples~/DI/Providers/GlobalMessageBusProvider.asset +14 -0
  101. package/Samples~/DI/Providers/GlobalMessageBusProvider.asset.meta +8 -0
  102. package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset +14 -0
  103. package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset.meta +8 -0
  104. package/Samples~/DI/Providers.meta +8 -0
  105. package/Samples~/DI/README.md +51 -0
  106. package/Samples~/DI/README.md.meta +7 -0
  107. package/Samples~/DI/Reflex/SampleInstaller.cs +75 -0
  108. package/Samples~/DI/Reflex/SampleInstaller.cs.meta +11 -0
  109. package/Samples~/DI/Reflex.meta +8 -0
  110. package/Samples~/DI/VContainer/SampleLifetimeScope.cs +81 -0
  111. package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -0
  112. package/Samples~/DI/VContainer.meta +8 -0
  113. package/Samples~/DI/Zenject/SampleInstaller.cs +67 -0
  114. package/Samples~/DI/Zenject/SampleInstaller.cs.meta +11 -0
  115. package/Samples~/DI/Zenject.meta +8 -0
  116. package/Samples~/DI.meta +8 -0
  117. package/Samples~/Mini Combat/README.md +86 -28
  118. package/Samples~/Mini Combat/Walkthrough.md +41 -25
  119. package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs +12 -2
  120. package/Samples~/UI Buttons + Inspector/README.md +55 -12
  121. package/Samples~/UI Buttons + Inspector/README.md.meta +7 -0
  122. package/Tests/Runtime/Benchmarks/BenchmarkSession.cs +444 -0
  123. package/Tests/Runtime/Benchmarks/BenchmarkSession.cs.meta +11 -0
  124. package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs +94 -0
  125. package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs.meta +11 -0
  126. package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs +395 -0
  127. package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs.meta +11 -0
  128. package/Tests/Runtime/Benchmarks/PerformanceTests.cs +77 -429
  129. package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs +142 -0
  130. package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs.meta +12 -0
  131. package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef +50 -0
  132. package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef.meta +7 -0
  133. package/Tests/Runtime/Core/DefaultBusFallbackTests.cs +333 -0
  134. package/Tests/Runtime/Core/DefaultBusFallbackTests.cs.meta +11 -0
  135. package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs +278 -0
  136. package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs.meta +11 -0
  137. package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs +289 -0
  138. package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs.meta +11 -0
  139. package/Tests/Runtime/Core/Extensions.meta +8 -0
  140. package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs +57 -0
  141. package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs.meta +11 -0
  142. package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs +219 -0
  143. package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs.meta +11 -0
  144. package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs +204 -0
  145. package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs.meta +11 -0
  146. package/Tests/Runtime/Core/MessagingTestBase.cs +4 -4
  147. package/Tests/Runtime/Core/NominalTests.cs +2 -2
  148. package/Tests/Runtime/Core/SourceGeneratorNestedTests.cs +1 -1
  149. package/Tests/Runtime/Core/TypedShorthandTests.cs +2 -2
  150. package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs +1 -1
  151. package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +2 -4
  152. package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs +162 -0
  153. package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs.meta +11 -0
  154. package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset +16 -0
  155. package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset.meta +8 -0
  156. package/Tests/Runtime/Integrations/Reflex/Resources.meta +8 -0
  157. package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef +27 -0
  158. package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef.meta +7 -0
  159. package/Tests/Runtime/Integrations/Reflex.meta +8 -0
  160. package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs +140 -0
  161. package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs.meta +11 -0
  162. package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef +37 -0
  163. package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef.meta +7 -0
  164. package/Tests/Runtime/Integrations/VContainer.meta +8 -0
  165. package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef +37 -0
  166. package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef.meta +7 -0
  167. package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs +140 -0
  168. package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs.meta +11 -0
  169. package/Tests/Runtime/Integrations/Zenject.meta +8 -0
  170. package/Tests/Runtime/Integrations.meta +8 -0
  171. package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs +1 -1
  172. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +1 -1
  173. package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs +1 -1
  174. package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs +64 -0
  175. package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs.meta +12 -0
  176. package/Tests/Runtime/TestUtilities.meta +9 -0
  177. package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs +57 -0
  178. package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs.meta +11 -0
  179. package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs +107 -0
  180. package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs.meta +12 -0
  181. package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs +210 -0
  182. package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs.meta +12 -0
  183. package/Tests/Runtime/Unity.meta +9 -0
  184. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef +3 -1
  185. package/package.json +1 -1
@@ -5,6 +5,7 @@ namespace DxMessaging.Editor.CustomEditors
5
5
  using System.Linq;
6
6
  using Core;
7
7
  using Core.Diagnostics;
8
+ using Core.MessageBus;
8
9
  using Core.Messages;
9
10
  using Unity;
10
11
  using UnityEditor;
@@ -107,18 +108,26 @@ namespace DxMessaging.Editor.CustomEditors
107
108
  }
108
109
  }
109
110
 
110
- if (!MessageHandler.MessageBus.DiagnosticsMode)
111
+ IMessageBus globalBus = MessageHandler.MessageBus;
112
+ if (globalBus is not MessageBus concreteBus)
113
+ {
114
+ EditorGUILayout.HelpBox(
115
+ "Global diagnostics controls are unavailable because the active global bus is not the default DxMessaging MessageBus implementation.",
116
+ MessageType.Info
117
+ );
118
+ }
119
+ else if (!concreteBus.DiagnosticsMode)
111
120
  {
112
121
  if (GUILayout.Button("Enable Global Diagnostics"))
113
122
  {
114
- MessageHandler.MessageBus.DiagnosticsMode = true;
123
+ concreteBus.DiagnosticsMode = true;
115
124
  }
116
125
  }
117
126
  else
118
127
  {
119
128
  if (GUILayout.Button("Disable Global Diagnostics"))
120
129
  {
121
- MessageHandler.MessageBus.DiagnosticsMode = false;
130
+ concreteBus.DiagnosticsMode = false;
122
131
  }
123
132
  else
124
133
  {
@@ -130,7 +139,7 @@ namespace DxMessaging.Editor.CustomEditors
130
139
  "Global Messages",
131
140
  true
132
141
  );
133
- int totalGlobalMessages = MessageHandler.MessageBus._emissionBuffer.Count;
142
+ int totalGlobalMessages = concreteBus._emissionBuffer.Count;
134
143
  if (_globalBufferExpanded && totalGlobalMessages > 0)
135
144
  {
136
145
  int page = _globalBufferPaging;
@@ -163,8 +172,8 @@ namespace DxMessaging.Editor.CustomEditors
163
172
  }
164
173
  }
165
174
 
166
- MessageEmissionData[] pagedGlobalMessages = MessageHandler
167
- .MessageBus._emissionBuffer.Reverse()
175
+ MessageEmissionData[] pagedGlobalMessages = concreteBus
176
+ ._emissionBuffer.Reverse()
168
177
  .Skip(page * PageSize)
169
178
  .Take(PageSize)
170
179
  .ToArray();
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # DxMessaging for Unity β€” The Modern Event System
2
2
 
3
- [![Unity](https://img.shields.io/badge/Unity-2021.3+-black.svg)](https://unity.com/download)<br/>
3
+ [![Unity](https://img.shields.io/badge/Unity-2021.3+-black.svg)](https://unity.com/releases/editor)<br/>
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE.md)<br/>
5
5
  [![Version](https://img.shields.io/badge/version-2.0.0--rc27-green.svg)](package.json)<br/>
6
6
  [![Performance: OS-Specific Benchmarks](https://img.shields.io/badge/Performance-OS--specific-blueviolet.svg)](Docs/Performance.md)<br/>
@@ -32,17 +32,27 @@ Think of it as **the event system Unity should have built-in** β€” one that actu
32
32
 
33
33
  ## 30-Second Elevator Pitch
34
34
 
35
- **Problem:** In Unity, you're stuck with manual event management (memory leaks!), tight coupling (everything knows everything!), or messy global event buses (no context, no control!).
35
+ ### If you've ever
36
36
 
37
- **Solution:** DxMessaging gives you three simple message types:
37
+ - Forgotten to unsubscribe from an event and spent hours debugging memory leaks
38
+ - Had UI code tangled with 15 different game systems
39
+ - Wondered "which event fired when?" with no way to see message flow
40
+ - Copy-pasted event boilerplate dozens of times
38
41
 
39
- 1. **Untargeted** - "Hey everyone!" (global events)
40
- 1. **Targeted** - "Hey YOU!" (commands to specific objects)
41
- 1. **Broadcast** - "I did something!" (events from sources)
42
+ #### Then DxMessaging solves your problems
42
43
 
43
- **Result:** Zero memory leaks (automatic lifecycle), zero coupling (no references needed), full observability (see everything in Inspector), and predictable execution (priority-based ordering).
44
+ - **Zero memory leaks** - automatic lifecycle management, no manual unsubscribe
45
+ - **Zero coupling** - systems communicate without knowing each other exist
46
+ - **Full visibility** - see every message in the Inspector with timestamps and payloads
47
+ - **Complete control** - priority-based ordering, validation, and interception
44
48
 
45
- **One line:** It's like C# events, but with superpowers and no footguns. πŸš€
49
+ ##### Three simple message types
50
+
51
+ 1. **Untargeted** - "Everyone listen!" (pause game, settings changed)
52
+ 1. **Targeted** - "Tell Player to heal" (commands to specific entities)
53
+ 1. **Broadcast** - "Enemy took damage" (events others can observe)
54
+
55
+ **One line:** It's the event system Unity should have shipped with - type-safe, leak-proof, and actually debuggable. πŸš€
46
56
 
47
57
  ---
48
58
 
@@ -103,6 +113,57 @@ msg.EmitComponentTargeted(chestComponent);
103
113
 
104
114
  ---
105
115
 
116
+ ## πŸ”§ Dependency Injection (DI) Compatible
117
+
118
+ **Using Zenject, VContainer, or Reflex?** DxMessaging is fully DI-compatible out of the box!
119
+
120
+ ```csharp
121
+ // Inject IMessageBus in any class
122
+ public class PlayerService : IInitializable, IDisposable
123
+ {
124
+ private readonly MessageRegistrationLease _lease;
125
+
126
+ public PlayerService(IMessageRegistrationBuilder builder)
127
+ {
128
+ // Builder automatically resolves your container-managed bus
129
+ _lease = builder.Build(new MessageRegistrationBuildOptions
130
+ {
131
+ Configure = token => token.RegisterUntargeted<PlayerSpawned>(OnSpawn)
132
+ });
133
+ }
134
+
135
+ public void Initialize() => _lease.Activate();
136
+ public void Dispose() => _lease.Dispose();
137
+ }
138
+ ```
139
+
140
+ ### Why use DI + Messaging?
141
+
142
+ - **DI for construction** β€” Inject services, repositories, managers via constructors
143
+ - **Messaging for events** β€” Reactive, decoupled communication for gameplay events
144
+ - **Best of both worlds** β€” Clean architecture with testable, isolated buses
145
+
146
+ #### Automatic integration for
147
+
148
+ - βœ… **Zenject/Extenject** β€” Full-featured DI with extensive Unity support
149
+ - βœ… **VContainer** β€” Lightweight, high-performance DI with scoped lifetimes
150
+ - βœ… **Reflex** β€” Minimal API, blazing-fast dependency injection
151
+
152
+ ##### Get started
153
+
154
+ - [Zenject Integration Guide](Docs/Integrations/Zenject.md) β€” Complete setup with examples
155
+ - [VContainer Integration Guide](Docs/Integrations/VContainer.md) β€” Scoped buses for scene isolation
156
+ - [Reflex Integration Guide](Docs/Integrations/Reflex.md) β€” Minimal, lightweight patterns
157
+
158
+ ##### Core DI concepts
159
+
160
+ - [Runtime Configuration](Docs/RuntimeConfiguration.md) β€” Setting message buses at runtime, re-binding registrations
161
+ - [Message Bus Providers](Docs/MessageBusProviders.md) β€” Provider system for design-time and runtime bus configuration
162
+
163
+ **Not using DI?** No problem! DxMessaging works perfectly standalone with zero dependencies.
164
+
165
+ ---
166
+
106
167
  ## Is DxMessaging Right for You
107
168
 
108
169
  ### βœ… Use DxMessaging When
@@ -113,6 +174,7 @@ msg.EmitComponentTargeted(chestComponent);
113
174
  - **You value observability** - Need to debug "what fired when?" or track message flow
114
175
  - **Teams/long-term maintenance** - Multiple developers, or you'll maintain this code for years
115
176
  - **You want decoupling** - Hate when UI classes need references to 15 different game systems
177
+ - **You're using DI frameworks** - Seamless integration with Zenject/VContainer/Reflex (see [DI Compatible](#-dependency-injection-di-compatible))
116
178
 
117
179
  ### ❌ Don't Use DxMessaging When
118
180
 
@@ -152,95 +214,194 @@ Looking for hard numbers? See OS-specific [Performance Benchmarks](Docs/Performa
152
214
 
153
215
  ## Why DxMessaging
154
216
 
155
- ### The Problem You Know
217
+ ### The Problems You've Probably Hit
218
+
219
+ #### Scenario 1: The Memory Leak Nightmare
220
+
221
+ You write this innocent-looking code:
222
+
223
+ ```csharp
224
+ public class GameUI : MonoBehaviour {
225
+ void OnEnable() {
226
+ GameManager.Instance.OnScoreChanged += UpdateScore;
227
+ }
228
+ // Oops, forgot OnDisable... leak! πŸ’€
229
+ }
230
+ ```
231
+
232
+ Months later: "Why is our game using 2GB of RAM after an hour?"
233
+
234
+ ##### Scenario 2: The Spaghetti Mess
156
235
 
157
236
  ```csharp
158
- // C# Events: Manual lifecycle hell
159
237
  public class GameUI : MonoBehaviour {
160
238
  [SerializeField] private Player player;
161
239
  [SerializeField] private EnemySpawner spawner;
240
+ [SerializeField] private InventorySystem inventory;
241
+ [SerializeField] private QuestSystem quests;
242
+ [SerializeField] private AudioManager audio;
243
+ // ... 15 more SerializeFields ...
162
244
 
163
245
  void Awake() {
164
246
  player.OnHealthChanged += UpdateHealth;
165
247
  spawner.OnWaveStart += ShowWave;
166
- }
167
-
168
- void OnDestroy() {
169
- // Easy to forget = memory leaks
170
- player.OnHealthChanged -= UpdateHealth;
171
- spawner.OnWaveStart -= ShowWave;
248
+ inventory.OnItemAdded += RefreshInventory;
249
+ quests.OnQuestCompleted += ShowQuestNotification;
250
+ // ... 20 more subscriptions ...
172
251
  }
173
252
  }
174
253
  ```
175
254
 
176
- Problems:
255
+ **Your UI now depends on EVERYTHING.** Good luck refactoring that.
256
+
257
+ ###### Scenario 3: The Debugging Black Hole
258
+
259
+ Player reports: "My health bar didn't update!"
260
+
261
+ You think: "Okay, which of the 47 events touching health failed? And in what order?"
177
262
 
178
- - ❌ Manual subscribe/unsubscribe (memory leaks waiting to happen)
179
- - ❌ Tight coupling (UI needs references to every system)
180
- - ❌ No execution order control
181
- - ❌ Impossible to debug ("which event fired when?")
263
+ **30 minutes later:** Still setting breakpoints everywhere...
264
+
265
+ ### Common Problems
266
+
267
+ - ❌ **Memory leaks** from forgotten unsubscribes (every Unity dev's nightmare)
268
+ - ❌ **Tight coupling** making refactoring terrifying ("change one thing, break five others")
269
+ - ❌ **No execution order control** ("why does the UI update before the player takes damage?")
270
+ - ❌ **Impossible to debug** ("what fired when?" has no answer)
271
+ - ❌ **Boilerplate overload** (write 50 lines for 3 events)
182
272
 
183
273
  ### The DxMessaging Solution
184
274
 
275
+ #### Same scenarios, zero pain
276
+
277
+ ##### Scenario 1: No More Memory Leaks
278
+
185
279
  ```csharp
186
- using DxMessaging.Core.Attributes;
187
- using DxMessaging.Core.Extensions;
188
- using DxMessaging.Unity;
280
+ public class GameUI : MessageAwareComponent {
281
+ protected override void RegisterMessageHandlers() {
282
+ base.RegisterMessageHandlers();
283
+ _ = Token.RegisterUntargeted<ScoreChanged>(UpdateScore);
284
+ }
285
+ // That's it! No manual cleanup needed.
286
+ // Token automatically handles OnEnable/OnDisable/OnDestroy
287
+ }
288
+ ```
289
+
290
+ **Automatic lifecycle = impossible to leak.** πŸŽ‰
291
+
292
+ ###### Scenario 2: No More Coupling
293
+
294
+ ```csharp
295
+ public class GameUI : MessageAwareComponent {
296
+ // Zero SerializeFields! Zero references!
297
+
298
+ protected override void RegisterMessageHandlers() {
299
+ base.RegisterMessageHandlers();
300
+ _ = Token.RegisterUntargeted<HealthChanged>(OnHealth);
301
+ _ = Token.RegisterUntargeted<WaveStarted>(OnWave);
302
+ _ = Token.RegisterUntargeted<ItemAdded>(OnItem);
303
+ // Listen to anything, from anywhere, no coupling
304
+ }
305
+ }
306
+ ```
307
+
308
+ **Your UI is now independent.** Swap systems freely without breaking anything.
309
+
310
+ ###### Scenario 3: Debugging is Built In
311
+
312
+ Open any `MessageAwareComponent` in the Inspector:
313
+
314
+ ```text
315
+ Message History (last 50):
316
+ [12:34:56] HealthChanged (amount: 25) β†’ Priority: 0
317
+ [12:34:55] ItemAdded (id: 42, count: 1) β†’ Priority: 5
318
+ [12:34:54] WaveStarted (wave: 3) β†’ Priority: 0
319
+
320
+ Active Registrations:
321
+ βœ“ HealthChanged (5 handlers)
322
+ βœ“ ItemAdded (2 handlers)
323
+ ```
189
324
 
190
- // 1. Define messages (clean, typed, immutable)
325
+ **See exactly what fired, when, and who handled it.** No guesswork.
326
+
327
+ ### How It Transforms Your Code
328
+
329
+ ```csharp
330
+ // 1. Define messages (clean, typed, discoverable)
191
331
  [DxTargetedMessage]
192
332
  [DxAutoConstructor]
193
333
  public readonly partial struct Heal { public readonly int amount; }
194
334
 
195
335
  // 2. Listen (automatic lifecycle - zero leaks)
196
- public class GameUI : MessageAwareComponent {
336
+ public class Player : MessageAwareComponent {
197
337
  protected override void RegisterMessageHandlers() {
198
338
  base.RegisterMessageHandlers();
199
339
  _ = Token.RegisterComponentTargeted<Heal>(this, OnHeal);
200
340
  }
201
341
 
202
- void OnHeal(ref Heal m) => UpdateHealthBar(m.amount);
342
+ void OnHeal(ref Heal m) {
343
+ health += m.amount;
344
+ Debug.Log($"Healed {m.amount}!");
345
+ }
203
346
  }
204
347
 
205
- // 3. Send (discoverable, type-safe)
206
- var heal = new Heal(10);
207
- heal.EmitGameObjectTargeted(gameObject);
348
+ // 3. Send (from anywhere - zero coupling)
349
+ var heal = new Heal(50);
350
+ heal.EmitComponentTargeted(playerComponent);
208
351
  ```
209
352
 
210
- Benefits:
353
+ #### What you get
211
354
 
212
- - βœ… **Zero memory leaks** - automatic lifecycle via tokens
213
- - βœ… **Full decoupling** - no direct references needed
214
- - βœ… **Predictable order** - priority-based execution
215
- - βœ… **Type-safe** - compile-time guarantees
216
- - βœ… **Observable** - built-in Inspector diagnostics
217
- - βœ… **Intercept & validate** - enforce rules before handlers run
355
+ - βœ… **Zero memory leaks** - tokens clean up automatically when components are destroyed
356
+ - βœ… **Zero coupling** - no SerializeFields, no GetComponent, no direct references
357
+ - βœ… **Full visibility** - see message flow in Inspector with timestamps and payloads
358
+ - βœ… **Predictable order** - priority-based execution (no more mystery race conditions)
359
+ - βœ… **Type-safe** - compile-time guarantees, refactor with confidence
360
+ - βœ… **Intercept & validate** - enforce rules before handlers run (clamp damage, block invalid input)
361
+ - βœ… **Extension points everywhere** - interceptors, handlers, post-processors with priorities
218
362
 
219
363
  ## Killer Features
220
364
 
221
- ### πŸš€ Performance: Zero-Allocation Design
365
+ Why DxMessaging is different:
366
+
367
+ ### πŸš€ Performance: Zero-Allocation, Zero-Leak Design
368
+
369
+ **The problem with normal events:** Boxing allocations, GC spikes, memory leaks from forgotten unsubscribes.
222
370
 
223
- Messages are `readonly struct` types passed by `ref` β€” no boxing, no GC pressure.
371
+ #### DxMessaging solution
224
372
 
225
373
  ```csharp
226
- void OnDamage(ref TookDamage msg) { // No allocations!
227
- health -= msg.amount;
374
+ void OnDamage(ref TookDamage msg) { // Pass by ref = zero allocations
375
+ health -= msg.amount; // No boxing, no GC pressure
228
376
  }
377
+ // Automatic cleanup = zero leaks, guaranteed
229
378
  ```
230
379
 
231
- ### 🎯 Three Message Types That Make Sense
380
+ **Real-world impact:** A game emitting 1000 messages/second uses **zero GC** with DxMessaging vs. 40KB/sec with boxed events.
381
+
382
+ ### 🎯 Three Message Types That Actually Make Sense
383
+
384
+ Most event systems force you into one pattern. DxMessaging gives you the right tool for each job:
232
385
 
233
386
  ```csharp
234
- // Untargeted: Global events anyone can hear
235
- [DxUntargetedMessage] public struct GamePaused { }
387
+ // Untargeted: "Everyone, listen up!" (global announcements)
388
+ [DxUntargetedMessage]
389
+ public struct GamePaused { }
390
+ // ↳ Perfect for: settings, scene transitions, global state
236
391
 
237
- // Targeted: Commands to specific entities
238
- [DxTargetedMessage] public struct Heal { public int amount; }
392
+ // Targeted: "Hey Player, do this!" (commands to specific entities)
393
+ [DxTargetedMessage]
394
+ public struct Heal { public int amount; }
395
+ // ↳ Perfect for: UI actions, direct commands, player input
239
396
 
240
- // Broadcast: Events from a source that others observe
241
- [DxBroadcastMessage] public struct TookDamage { public int amount; }
397
+ // Broadcast: "I took damage!" (events others can observe)
398
+ [DxBroadcastMessage]
399
+ public struct TookDamage { public int amount; }
400
+ // ↳ Perfect for: achievements, analytics, UI updates from entities
242
401
  ```
243
402
 
403
+ **Why this matters:** You're not forcing everything through one generic "Event<T>" pattern. Each message type has clear semantics.
404
+
244
405
  ### πŸ”„ The Message Pipeline
245
406
 
246
407
  Every message flows through 3 stages with priority control:
@@ -250,51 +411,136 @@ flowchart LR
250
411
  P[Producer] --> I[Interceptors<br/>validate/mutate]
251
412
  I --> H[Handlers<br/>main logic]
252
413
  H --> PP[Post-Processors<br/>analytics/logging]
253
- style I fill:#fff4e5,stroke:#f0b429
254
- style H fill:#e6f7ff,stroke:#1890ff
255
- style PP fill:#eef7ee,stroke:#52c41a
414
+ style I fill:#ffe7ba,stroke:#d48806,stroke-width:2px,color:#000
415
+ style H fill:#91d5ff,stroke:#096dd9,stroke-width:2px,color:#000
416
+ style PP fill:#b7eb8f,stroke:#389e0d,stroke-width:2px,color:#000
256
417
  ```
257
418
 
258
- ### 🎭 Listen to "All Targets" or "All Sources"
419
+ ### 🎭 Global Observers: Listen to EVERYTHING (Unique Feature!)
420
+
421
+ **The problem with normal events:** To track all player damage, enemy damage, and NPC damage, you need 3 separate event subscriptions.
259
422
 
260
- Perfect for analytics, achievements, and debugging:
423
+ **DxMessaging's superpower:** Subscribe ONCE to a message type, receive ALL instances with source information:
261
424
 
262
425
  ```csharp
263
- // Track ALL damage, regardless of source
426
+ // Track ALL damage from ANY source (players, enemies, NPCs, environment)
264
427
  _ = token.RegisterBroadcastWithoutSource<TookDamage>(
265
428
  (InstanceId source, TookDamage msg) => {
429
+ Debug.Log($"{source} took {msg.amount} damage!");
266
430
  Analytics.LogDamage(source, msg.amount);
431
+ CheckAchievements(source, msg.amount);
267
432
  }
268
433
  );
269
434
  ```
270
435
 
271
- ### πŸ›‘οΈ Interceptors: Validate Before Execution
436
+ #### Real-world use cases
437
+
438
+ - **Achievement system:** Track all kills, deaths, damage across the entire game
439
+ - **Combat log:** "Player took 25 damage, Enemy3 took 50 damage, Boss took 100 damage"
440
+ - **Analytics:** Aggregate stats from all entities without knowing about them upfront
441
+ - **Debug tools:** Watch ALL messages in the Inspector without instrumenting code
442
+
443
+ **Why this is revolutionary:** Traditional event buses require you to know entity types upfront. DxMessaging lets you observe dynamically.
444
+
445
+ ### πŸ›‘οΈ Interceptors: Validate Before Execution (Safety Built In)
446
+
447
+ **The problem with normal events:** Validation logic duplicated in every handler, or bugs when you forget.
448
+
449
+ **DxMessaging solution:** Validate ONCE before ANY handler runs:
272
450
 
273
451
  ```csharp
274
- // Clamp damage before any handler sees it
452
+ // ONE interceptor protects ALL handlers
275
453
  _ = token.RegisterBroadcastInterceptor<TookDamage>(
276
454
  (ref InstanceId src, ref TookDamage msg) => {
277
- if (msg.amount <= 0) return false; // Cancel
278
- msg = new TookDamage(Math.Min(msg.amount, 999)); // Clamp
455
+ if (msg.amount <= 0) return false; // Cancel invalid
456
+ if (msg.amount > 999) {
457
+ msg = new TookDamage(999); // Clamp excessive
458
+ }
459
+ if (IsGodModeActive(src)) return false; // Block damage
279
460
  return true;
280
- }
461
+ },
462
+ priority: -100 // Run FIRST
281
463
  );
464
+
465
+ // Now ALL handlers receive clean, validated data
466
+ _ = token.RegisterComponentTargeted<TookDamage>(player, OnDamage);
467
+ void OnDamage(ref TookDamage msg) {
468
+ // No validation needed - interceptor guarantees validity!
469
+ health -= msg.amount;
470
+ }
282
471
  ```
283
472
 
284
- ### πŸ” Built-in Inspector Diagnostics
473
+ #### Real-world use cases
474
+
475
+ - Clamp/normalize values (damage, healing, speeds)
476
+ - Enforce game rules ("can't heal above max health")
477
+ - Block messages during cutscenes
478
+ - Log/audit sensitive actions
479
+
480
+ ### πŸ” Built-in Inspector Diagnostics (Actually Debuggable!)
481
+
482
+ **The problem with normal events:** "Which event fired? When? Who handled it? In what order?" = 🀷
483
+
484
+ **DxMessaging solution:** Click any `MessageAwareComponent` in the Inspector:
485
+
486
+ #### Message History (last 50)
285
487
 
286
- See message history, handler counts, and registrations live in the Unity Inspector. For screenshots and details, see Unity Integration β†’ Diagnostics.
488
+ - `[12:34:56.123] HealthChanged`
489
+ - amount: 25
490
+ - priority: 0
491
+ - handlers: 3
492
+ - `[12:34:55.987] ItemAdded`
493
+ - itemId: 42, count: 1
494
+ - priority: 5
495
+ - handlers: 2
287
496
 
288
- ### 🏝️ Local Bus Islands for Testing
497
+ ##### Active Registrations
289
498
 
290
- Isolate subsystems with their own message buses:
499
+ - βœ“ HealthChanged (priority: 0, called: 847 times)
500
+ - βœ“ ItemAdded (priority: 5, called: 23 times)
501
+ - βœ“ TookDamage (priority: 10, called: 1,203 times)
502
+
503
+ #### Real-world debugging scenarios
504
+
505
+ - "Did my message fire?" β†’ Check history, see timestamp
506
+ - "Why didn't my handler run?" β†’ Check registrations, see if it's active
507
+ - "What's firing too often?" β†’ Sort by call count
508
+ - "What's the execution order?" β†’ Sort by priority
509
+
510
+ **No more:** Setting 50 breakpoints and stepping through code for 30 minutes.
511
+
512
+ ### 🏝️ Local Bus Islands for Testing (Actually Testable!)
513
+
514
+ **The problem with normal events:** Global static events contaminate tests. Mock hell. Flaky tests.
515
+
516
+ **DxMessaging solution:** Each test gets its own isolated message bus:
291
517
 
292
518
  ```csharp
293
- var testBus = new MessageBus();
294
- var token = MessageRegistrationToken.Create(handler, testBus);
295
- // Messages here don't affect the global bus!
519
+ [Test]
520
+ public void TestAchievementSystem() {
521
+ // Create isolated bus - zero global state
522
+ var testBus = new MessageBus();
523
+ var handler = new MessageHandler(new InstanceId(1), testBus) { active = true };
524
+ var token = MessageRegistrationToken.Create(handler, testBus);
525
+
526
+ // Test in isolation
527
+ _ = token.RegisterBroadcastWithoutSource<EnemyKilled>(achievements.OnKill);
528
+
529
+ var msg = new EnemyKilled("Boss");
530
+ msg.EmitGameObjectBroadcast(enemy, testBus); // Only this test sees it
531
+
532
+ Assert.IsTrue(achievements.Unlocked("BossSlayer"));
533
+ }
534
+ // Bus destroyed, zero cleanup needed
296
535
  ```
297
536
 
537
+ #### Why this matters
538
+
539
+ - Tests don't interfere with each other
540
+ - No "arrange/act/cleanup" boilerplate
541
+ - No mocking frameworks needed
542
+ - Parallel test execution works perfectly
543
+
298
544
  ## Documentation
299
545
 
300
546
  ### πŸŽ“ Learn
@@ -325,9 +571,64 @@ Important: Inheritance with MessageAwareComponent
325
571
  - If you need to opt out of string demos, override `RegisterForStringMessages => false` instead of skipping the base call.
326
572
  - Don’t hide Unity methods with `new` (e.g., `new void OnEnable()`); always `override` and call `base.*`.
327
573
 
574
+ ### 🧩 DI Framework Integrations
575
+
576
+ DxMessaging works standalone (zero dependencies) or with any major DI framework. For detailed setup guides and code examples:
577
+
578
+ - **[Zenject Integration Guide](Docs/Integrations/Zenject.md)** β€” Full-featured DI with extensive Unity support
579
+ - **[VContainer Integration Guide](Docs/Integrations/VContainer.md)** β€” Lightweight DI with scoped lifetimes for scene isolation
580
+ - **[Reflex Integration Guide](Docs/Integrations/Reflex.md)** β€” Minimal API, blazing-fast performance
581
+
582
+ #### Core DI concepts
583
+
584
+ - **[Runtime Configuration](Docs/RuntimeConfiguration.md)** β€” Setting and overriding message buses at runtime, re-binding registrations
585
+ - **[Message Bus Providers](Docs/MessageBusProviders.md)** β€” Provider system and MessageBusProviderHandle for flexible bus configuration
586
+
587
+ Each guide includes:
588
+
589
+ - βœ… Complete setup instructions with installers
590
+ - βœ… Multiple usage patterns (plain classes, MonoBehaviours, direct injection)
591
+ - βœ… Testing examples with isolated buses
592
+ - βœ… Advanced patterns (pooling, scene scopes, signal bridges)
593
+
594
+ See the [πŸ”§ DI Compatible section](#-dependency-injection-di-compatible) above for a quick overview.
595
+
328
596
  ### πŸ†š Comparisons
329
597
 
330
- - [Compare with C# events, UnityEvents, and SendMessage](Docs/Comparisons.md)
598
+ - [Compare with Other Unity Messaging Frameworks](Docs/Comparisons.md) β€” In-depth comparison with UniRx, MessagePipe, Zenject Signals, C# events, UnityEvents, and more
599
+ - [Scriptable Object Architecture (SOA) Compatibility](Docs/Patterns.md#14-compatibility-with-scriptable-object-architecture-soa) β€” Migration patterns and interoperability with SOA
600
+
601
+ #### Quick Framework Comparison
602
+
603
+ | Framework | Best For | Key Strength | Unity Support | Learning Curve |
604
+ | ------------------- | --------------------------------- | -------------------------------- | ------------------ | -------------- |
605
+ | **DxMessaging** | Unity pub/sub with lifecycle mgmt | Inspector debugging + control | βœ… Built for Unity | ⭐⭐⭐ |
606
+ | **UniRx** | Complex event stream transforms | Reactive operators (LINQ) | βœ… Built for Unity | ⭐⭐ |
607
+ | **MessagePipe** | High-performance DI messaging | Highest throughput (97M ops/sec) | βœ… Built for Unity | ⭐⭐⭐⭐ |
608
+ | **Zenject Signals** | DI-integrated messaging | Zenject ecosystem | βœ… Built for Unity | ⭐⭐ |
609
+ | **C# Events** | Simple, local communication | Minimal overhead | βœ… Native C# | ⭐⭐⭐⭐⭐ |
610
+
611
+ ##### Choose DxMessaging when you want
612
+
613
+ - Unity-first design with GameObject/Component targeting
614
+ - Automatic lifecycle management (zero memory leaks)
615
+ - Inspector debugging to see message flow and history
616
+ - Execution order control (priority-based handlers)
617
+ - Message validation/interception pipeline
618
+ - Global observers (listen to all message instances)
619
+ - Post-processing stage (analytics, logging after handlers)
620
+ - No dependencies, plug-and-play setup
621
+
622
+ See [full comparison](Docs/Comparisons.md) for detailed analysis with code examples, performance benchmarks, and decision guides.
623
+
624
+ > **πŸ“¦ Using Scriptable Object Architecture (SOA)?**
625
+ >
626
+ > DxMessaging can work alongside or replace SOA patterns. See [SOA Compatibility Guide](Docs/Patterns.md#14-compatibility-with-scriptable-object-architecture-soa) for:
627
+ >
628
+ > - Fair comparison of SOA vs. DxMessaging
629
+ > - Migration patterns from GameEvent/FloatVariable to DxMessaging
630
+ > - How to use both systems together (SOs for configs, DxMessaging for events)
631
+ > - When to keep using ScriptableObjects (immutable design data)
331
632
 
332
633
  ### πŸ“– Reference
333
634
 
@@ -400,6 +701,26 @@ For OS-specific benchmark tables generated by PlayMode tests, see [Performance B
400
701
 
401
702
  ## Comparison Table
402
703
 
704
+ ### Comparison with Unity Messaging Frameworks
705
+
706
+ | Feature | DxMessaging | UniRx | MessagePipe | Zenject Signals |
707
+ | ------------------------ | ------------------ | ------------------ | ------------------ | ------------------ |
708
+ | **Unity Compatibility** | βœ… Built for Unity | βœ… Built for Unity | βœ… Built for Unity | βœ… Built for Unity |
709
+ | **Decoupling** | βœ… Full | βœ… Full | βœ… Full | βœ… Full |
710
+ | **Lifecycle Safety** | βœ… Auto | ⚠️ Manual | ⚠️ Manual | ⚠️ DI-managed |
711
+ | **Execution Order** | βœ… Priority | ❌ None | ❌ None | ❌ None |
712
+ | **Type Safety** | βœ… Strong | βœ… Strong | βœ… Strong | βœ… Strong |
713
+ | **Inspector Debug** | βœ… Built-in | ❌ No | ❌ No | ❌ No |
714
+ | **GameObject Targeting** | βœ… Yes | ❌ No | ❌ No | ❌ No |
715
+ | **Global Observers** | βœ… Yes | ❌ No | ❌ No | ❌ No |
716
+ | **Interceptors** | βœ… Pipeline | ❌ No | ⚠️ Filters | ❌ No |
717
+ | **Post-Processing** | βœ… Dedicated | ❌ No | ⚠️ Filters | ❌ No |
718
+ | **Stream Operators** | ❌ No | βœ… Extensive | ❌ No | ⚠️ With UniRx |
719
+ | **Performance** | βœ… Good (14M) | βœ… Good (18M) | βœ… Best (97M) | ⚠️ Moderate (2.5M) |
720
+ | **Dependencies** | βœ… None | ⚠️ UniTask | βœ… None | ⚠️ Zenject |
721
+
722
+ ### Comparison with Traditional Approaches
723
+
403
724
  | Feature | DxMessaging | C# Events | UnityEvents | Static Event Bus |
404
725
  | ---------------------- | ------------- | ------------ | ------------- | ---------------- |
405
726
  | **Decoupling** | βœ… Full | ❌ Tight | ⚠️ Hidden | βœ… Yes |
@@ -5,3 +5,7 @@ using System.Runtime.CompilerServices;
5
5
  AllInternalsVisible = true
6
6
  )]
7
7
  [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Editor")]
8
+ [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime")]
9
+ [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.Reflex")]
10
+ [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.VContainer")]
11
+ [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.Zenject")]