com.wallstop-studios.dxmessaging 2.0.0 → 2.1.1

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 (183) 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 +1229 -146
  10. package/Docs/Compatibility.md +27 -0
  11. package/Docs/DesignAndArchitecture.md +41 -34
  12. package/Docs/EmitShorthands.md +34 -0
  13. package/Docs/Helpers.md +91 -76
  14. package/Docs/Index.md +28 -25
  15. package/Docs/Install.md +29 -6
  16. package/Docs/Integrations/Reflex.md +292 -0
  17. package/{package-lock.json.meta → Docs/Integrations/Reflex.md.meta} +1 -1
  18. package/Docs/Integrations/VContainer.md +324 -0
  19. package/Docs/Integrations/VContainer.md.meta +7 -0
  20. package/Docs/Integrations/Zenject.md +333 -0
  21. package/Docs/Integrations/Zenject.md.meta +7 -0
  22. package/{Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.pdb.meta → Docs/Integrations.meta} +2 -1
  23. package/Docs/InterceptorsAndOrdering.md +371 -17
  24. package/Docs/ListeningPatterns.md +206 -0
  25. package/Docs/MessageBusProviders.md +496 -0
  26. package/Docs/MessageBusProviders.md.meta +7 -0
  27. package/Docs/MessageTypes.md +27 -0
  28. package/Docs/MigrationGuide.md +45 -0
  29. package/Docs/Patterns.md +286 -0
  30. package/Docs/Performance.md +9 -9
  31. package/Docs/QuickReference.md +31 -0
  32. package/Docs/QuickStart.md +1 -2
  33. package/Docs/RuntimeConfiguration.md +407 -0
  34. package/Docs/RuntimeConfiguration.md.meta +7 -0
  35. package/Docs/UnityIntegration.md +3 -1
  36. package/Docs/VisualGuide.md +206 -157
  37. package/Editor/CustomEditors/MessagingComponentEditor.cs +15 -6
  38. package/README.md +148 -26
  39. package/Runtime/AssemblyInfo.cs +4 -0
  40. package/Runtime/Core/Attributes/DxAutoConstructorAttribute.cs +1 -1
  41. package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs +1 -1
  42. package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +1 -1
  43. package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs +1 -1
  44. package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs +1 -1
  45. package/Runtime/Core/Extensions/MessageBusExtensions.cs +253 -0
  46. package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -0
  47. package/Runtime/Core/Extensions/MessageExtensions.cs +137 -89
  48. package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs +23 -0
  49. package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -0
  50. package/Runtime/Core/MessageBus/IMessageBusProvider.cs +14 -0
  51. package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -0
  52. package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +18 -0
  53. package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -0
  54. package/Runtime/Core/MessageBus/MessageBusRebindMode.cs +26 -0
  55. package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -0
  56. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +383 -0
  57. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -0
  58. package/Runtime/Core/MessageHandler.cs +198 -27
  59. package/Runtime/Core/MessageRegistrationToken.cs +67 -25
  60. package/Runtime/Core/Messages/IBroadcastMessage.cs +1 -1
  61. package/Runtime/Core/Messages/ITargetedMessage.cs +1 -1
  62. package/Runtime/Core/Messages/IUntargetedMessage.cs +1 -1
  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 +175 -9
  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 +79 -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 +65 -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 +5 -7
  118. package/Samples~/Mini Combat/Walkthrough.md +18 -24
  119. package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs +12 -2
  120. package/Samples~/UI Buttons + Inspector/README.md.meta +7 -0
  121. package/Tests/Runtime/Benchmarks/BenchmarkSession.cs +444 -0
  122. package/Tests/Runtime/Benchmarks/BenchmarkSession.cs.meta +11 -0
  123. package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs +94 -0
  124. package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs.meta +11 -0
  125. package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs +395 -0
  126. package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs.meta +11 -0
  127. package/Tests/Runtime/Benchmarks/PerformanceTests.cs +77 -429
  128. package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs +142 -0
  129. package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs.meta +12 -0
  130. package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef +50 -0
  131. package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef.meta +7 -0
  132. package/Tests/Runtime/Core/DefaultBusFallbackTests.cs +333 -0
  133. package/Tests/Runtime/Core/DefaultBusFallbackTests.cs.meta +11 -0
  134. package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs +278 -0
  135. package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs.meta +11 -0
  136. package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs +289 -0
  137. package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs.meta +11 -0
  138. package/Tests/Runtime/Core/Extensions.meta +8 -0
  139. package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs +57 -0
  140. package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs.meta +11 -0
  141. package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs +219 -0
  142. package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs.meta +11 -0
  143. package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs +204 -0
  144. package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs.meta +11 -0
  145. package/Tests/Runtime/Core/MessagingTestBase.cs +4 -4
  146. package/Tests/Runtime/Core/NominalTests.cs +2 -2
  147. package/Tests/Runtime/Core/TypedShorthandTests.cs +2 -2
  148. package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs +1 -1
  149. package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +2 -4
  150. package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs +162 -0
  151. package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs.meta +11 -0
  152. package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset +16 -0
  153. package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset.meta +8 -0
  154. package/Tests/Runtime/Integrations/Reflex/Resources.meta +8 -0
  155. package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef +27 -0
  156. package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef.meta +7 -0
  157. package/Tests/Runtime/Integrations/Reflex.meta +8 -0
  158. package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs +140 -0
  159. package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs.meta +11 -0
  160. package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef +37 -0
  161. package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef.meta +7 -0
  162. package/Tests/Runtime/Integrations/VContainer.meta +8 -0
  163. package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef +37 -0
  164. package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef.meta +7 -0
  165. package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs +140 -0
  166. package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs.meta +11 -0
  167. package/Tests/Runtime/Integrations/Zenject.meta +8 -0
  168. package/Tests/Runtime/Integrations.meta +8 -0
  169. package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs +1 -1
  170. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +1 -1
  171. package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs +1 -1
  172. package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs +64 -0
  173. package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs.meta +12 -0
  174. package/Tests/Runtime/TestUtilities.meta +9 -0
  175. package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs +57 -0
  176. package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs.meta +11 -0
  177. package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs +107 -0
  178. package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs.meta +12 -0
  179. package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs +210 -0
  180. package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs.meta +12 -0
  181. package/Tests/Runtime/Unity.meta +9 -0
  182. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef +3 -1
  183. package/package.json +1 -1
@@ -15,3 +15,30 @@ Notes
15
15
 
16
16
  - RP‑agnostic: DxMessaging does not depend on rendering APIs; it works equally across Built‑In, URP, and HDRP.
17
17
  - Minimum version is governed by the package manifest (`unity`: 2021.3). Newer LTS versions are expected to work.
18
+
19
+ ## Architecture Pattern Compatibility
20
+
21
+ ### Scriptable Object Architecture (SOA)
22
+
23
+ DxMessaging can work alongside Scriptable Object Architecture patterns, though SOA has documented limitations. See [Pattern 14: SOA Compatibility](Patterns.md#14-compatibility-with-scriptable-object-architecture-soa) for detailed integration strategies, code examples, and migration paths.
24
+
25
+ #### Quick summary
26
+
27
+ - ✅ **Compatible** - DxMessaging can bridge with SOA systems
28
+ - ⚠️ **Not recommended** - SOA has scalability and maintainability concerns ([detailed critique](https://github.com/cathei/AntiScriptableObjectArchitecture))
29
+ - ✅ **Best practice** - Use ScriptableObjects for immutable design data, DxMessaging for runtime events
30
+ - → See [SOA Integration Patterns](Patterns.md#14-compatibility-with-scriptable-object-architecture-soa) for three coexistence strategies with code examples
31
+
32
+ ### Dependency Injection (DI) Frameworks
33
+
34
+ DxMessaging integrates seamlessly with popular DI frameworks:
35
+
36
+ - **Zenject** - See [Zenject Integration Guide](Integrations/Zenject.md)
37
+ - **VContainer** - See [VContainer Integration Guide](Integrations/VContainer.md)
38
+ - **Reflex** - See [Reflex Integration Guide](Integrations/Reflex.md)
39
+
40
+ DI and DxMessaging complement each other: DI manages dependencies/services, DxMessaging handles event communication.
41
+
42
+ ### Other Unity Frameworks
43
+
44
+ For comparisons with other messaging/event frameworks (UniRx, MessagePipe, Zenject Signals, etc.), see [Framework Comparisons](Comparisons.md).
@@ -49,42 +49,49 @@ DxMessaging was built with these principles:
49
49
 
50
50
  ## Architecture Overview
51
51
 
52
- ```text
53
- ┌─────────────────────────────────────────────────────────────┐
54
- │ Application │
55
- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
56
- │ │ Component A │ │ Component B │ │ Component C │ │
57
- │ │ │ │ │ │ │ │
58
- │ │ Token.Reg() │ │ Token.Reg() │ │ Token.Reg() │ │
59
- │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
60
- │ │ │ │ │
61
- │ └─────────────────┼─────────────────┘ │
62
- │ ▼ │
63
- │ ┌─────────────────────────┐ │
64
- │ │ MessageRegistrationToken│ │
65
- │ │ │ │
66
- │ │ Stages registrations │ │
67
- │ │ • Enable/Disable │ │
68
- │ │ • Lifecycle management │ │
69
- │ └────────────┬────────────┘ │
70
- │ ▼ │
71
- │ ┌─────────────────────────┐ │
72
- │ │ MessageHandler │ │
73
- │ │ │ │
74
- │ │ Per-component handler │ │
75
- │ │ Active/Inactive state │ │
76
- │ └────────────┬────────────┘ │
77
- │ ▼ │
78
- │ ┌─────────────────────────┐ │
79
- │ │ MessageBus │ │
80
- │ │ │ │
81
- │ │ Interceptors │ │
82
- │ │ Handlers │ │
83
- │ │ Post-Processors │ │
84
- │ └─────────────────────────┘ │
85
- └─────────────────────────────────────────────────────────────┘
52
+ ```mermaid
53
+ %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#fff','primaryTextColor':'#000','primaryBorderColor':'#000','lineColor':'#2563eb','secondaryColor':'#fff','tertiaryColor':'#fff','edgeLabelBackground':'#fff'}}}%%
54
+ flowchart TB
55
+ subgraph App["<b>Application Layer</b>"]
56
+ CompA[Component A<br/>Token.Reg]
57
+ CompB[Component B<br/>Token.Reg]
58
+ CompC[Component C<br/>Token.Reg]
59
+ end
60
+
61
+ subgraph Token["<b>Registration Layer</b>"]
62
+ MRT[MessageRegistrationToken<br/>• Stages registrations<br/>• Enable/Disable<br/>• Lifecycle management]
63
+ end
64
+
65
+ subgraph Handler["<b>Handler Layer</b>"]
66
+ MH[MessageHandler<br/>• Per-component handler<br/>• Active/Inactive state]
67
+ end
68
+
69
+ subgraph Bus["<b>Message Bus Layer</b>"]
70
+ MB[MessageBus<br/>• Interceptors<br/>• Handlers<br/>• Post-Processors]
71
+ end
72
+
73
+ CompA ==> MRT
74
+ CompB ==> MRT
75
+ CompC ==> MRT
76
+ MRT ==> MH
77
+ MH ==> MB
78
+
79
+ style App fill:#bae7ff,stroke:#0050b3,stroke-width:3px,color:#000
80
+ style Token fill:#ffe7ba,stroke:#d48806,stroke-width:3px,color:#000
81
+ style Handler fill:#d3adf7,stroke:#531dab,stroke-width:3px,color:#000
82
+ style Bus fill:#b7eb8f,stroke:#389e0d,stroke-width:3px,color:#000
83
+ style MRT fill:#ffe7ba,stroke:#d48806,stroke-width:2px,color:#000
84
+ style MH fill:#d3adf7,stroke:#531dab,stroke-width:2px,color:#000
85
+ style MB fill:#b7eb8f,stroke:#389e0d,stroke-width:2px,color:#000
86
86
  ```
87
87
 
88
+ ### Layer Responsibilities
89
+
90
+ 1. **Application Layer** - Your Unity components register message handlers
91
+ 1. **Registration Layer** - Token manages handler lifecycle (enable/disable/cleanup)
92
+ 1. **Handler Layer** - Per-component state management (active/inactive)
93
+ 1. **Message Bus Layer** - Routes messages through interceptors → handlers → post-processors
94
+
88
95
  ## Performance Optimizations
89
96
 
90
97
  - Struct messages passed by `ref` to avoid copying and GC.
@@ -45,6 +45,40 @@ var damage = new TookDamage(5);
45
45
  damage.EmitFrom(enemy); // Broadcast: listeners interested in enemy damage receive this
46
46
  ```
47
47
 
48
+ ### Bus-First Helpers
49
+
50
+ Prefer injecting `IMessageBus` (or `IMessageRegistrationBuilder`) in DI scenarios and use the bus-first extensions for parity with the shorthands:
51
+
52
+ ```csharp
53
+ using DxMessaging.Core.Extensions;
54
+ using DxMessaging.Core.Attributes;
55
+
56
+ public sealed class ScoreReporter
57
+ {
58
+ private readonly IMessageBus messageBus;
59
+
60
+ public ScoreReporter(IMessageBus messageBus)
61
+ {
62
+ this.messageBus = messageBus;
63
+ }
64
+
65
+ public void Report(int value)
66
+ {
67
+ ScoreChanged message = new ScoreChanged(value);
68
+ messageBus.EmitUntargeted(ref message);
69
+ }
70
+ }
71
+
72
+ [DxUntargetedMessage]
73
+ [DxAutoConstructor]
74
+ public readonly partial struct ScoreChanged
75
+ {
76
+ public readonly int Value;
77
+ }
78
+ ```
79
+
80
+ These helpers mirror the struct/class/targeted/broadcast overloads available on message instances. They keep DI-friendly services aligned with the same dispatch path as Unity shorthands.
81
+
48
82
  ## Understanding Each Shorthand
49
83
 
50
84
  ### `Emit()` — Global Broadcast (Untargeted)
package/Docs/Helpers.md CHANGED
@@ -186,34 +186,32 @@ public readonly partial struct ComplexMessage
186
186
 
187
187
  ## Why Use Attributes Instead of Manual Implementation
188
188
 
189
- ### Manual Way (Verbose, Error-Prone)
189
+ ### Attribute Definition (Clean, Automatic)
190
190
 
191
191
  ```csharp
192
- public readonly struct Heal : ITargetedMessage<Heal>
192
+ [DxTargetedMessage]
193
+ [DxAutoConstructor]
194
+ public readonly partial struct Heal
193
195
  {
194
196
  public readonly int amount;
195
-
196
- // You write this yourself (boring!)
197
- public Heal(int amount)
198
- {
199
- this.amount = amount;
200
- }
201
-
202
- // Required plumbing (easy to mess up!)
203
- public Type MessageType => typeof(Heal);
204
197
  }
205
198
  ```
206
199
 
207
- ### Attribute Way (Clean, Automatic)
200
+ ### What the generator emits (for reference)
208
201
 
209
202
  ```csharp
210
- [DxTargetedMessage]
211
- [DxAutoConstructor]
212
- public readonly partial struct Heal
203
+ // Auto-generated by DxMessaging (no need to hand-write this)
204
+ public readonly partial struct Heal : ITargetedMessage<Heal>
213
205
  {
214
206
  public readonly int amount;
207
+
208
+ public Heal(int amount)
209
+ {
210
+ this.amount = amount;
211
+ }
212
+
213
+ public Type MessageType => typeof(Heal);
215
214
  }
216
- // Constructor and plumbing generated automatically!
217
215
  ```
218
216
 
219
217
  #### Benefits
@@ -223,14 +221,28 @@ public readonly partial struct Heal
223
221
  - ✅ **Cleaner** - Focus on data, not boilerplate
224
222
  - ✅ **Refactor-safe** - Add field? Constructor updates automatically!
225
223
 
226
- ## Complete Example: Before & After
224
+ ## Complete Example: Attribute Definition vs Generated Output
227
225
 
228
- ### Before (Manual - 20 lines)
226
+ ### Attribute Definition (8 lines)
229
227
 
230
228
  ```csharp
231
- using DxMessaging.Core.Messages;
229
+ using DxMessaging.Core.Attributes;
232
230
 
233
- public readonly struct PlayerDamaged : IBroadcastMessage<PlayerDamaged>
231
+ [DxBroadcastMessage]
232
+ [DxAutoConstructor]
233
+ public readonly partial struct PlayerDamaged
234
+ {
235
+ public readonly int amount;
236
+ public readonly string damageType;
237
+ public readonly GameObject source;
238
+ }
239
+ ```
240
+
241
+ ### Generated Output (20 lines you never write)
242
+
243
+ ```csharp
244
+ // Auto-generated by DxMessaging (for reference only)
245
+ public readonly partial struct PlayerDamaged : IBroadcastMessage<PlayerDamaged>
234
246
  {
235
247
  public readonly int amount;
236
248
  public readonly string damageType;
@@ -247,65 +259,76 @@ public readonly struct PlayerDamaged : IBroadcastMessage<PlayerDamaged>
247
259
  }
248
260
  ```
249
261
 
250
- ### After (Attributes - 9 lines!)
262
+ ### Result
251
263
 
252
- ```csharp
253
- using DxMessaging.Core.Attributes;
264
+ - ✅ Same functionality
265
+ - ✅ Less code to maintain
266
+ - ✅ Automatically updates when you add/remove fields
267
+ - ✅ Works for class messages too
268
+ - ✅ Zero effort once you mark the struct partial
254
269
 
255
- [DxBroadcastMessage]
270
+ ## Advanced: Manual Implementation (When Attributes Aren't Enough)
271
+
272
+ Attributes cover almost every scenario. If you intentionally drop `[DxTargetedMessage]`, `[DxUntargetedMessage]`, or `[DxBroadcastMessage]`, you'll need to hand-write the interface implementations and constructors shown in the “generated output” examples. Keep the attributes unless you have a very specific data-backed reason not to.
273
+
274
+ ### Generic Message Interfaces (Zero-Boxing for Structs)
275
+
276
+ `readonly struct` messages marked with the attributes already implement the generic interfaces, so emissions stay allocation-free. You get the same performance characteristics as the manual approach without writing any plumbing.
277
+
278
+ ```csharp
279
+ [DxTargetedMessage]
256
280
  [DxAutoConstructor]
257
- public readonly partial struct PlayerDamaged
281
+ public readonly partial struct Heal
258
282
  {
259
283
  public readonly int amount;
260
- public readonly string damageType;
261
- public readonly GameObject source;
262
284
  }
263
285
  ```
264
286
 
265
- **Result:** Same functionality, 55% less code, zero boilerplate!
287
+ ### "Do I HAVE to use attributes?"
266
288
 
267
- ## Advanced: Manual Implementation (When Attributes Aren't Enough)
289
+ Technically no—but without them you must write the constructor, interface implementation, and `MessageType` property yourself (for speed, you can optionally leave this off, but it might box on certain call paths). Leaving the attributes on keeps everything consistent for the whole team.
268
290
 
269
- Sometimes you might want full control and skip source generators. You can implement interfaces manually:
291
+ ```csharp
292
+ [DxUntargetedMessage]
293
+ [DxAutoConstructor]
294
+ public readonly partial struct MyMsg { }
295
+ ```
270
296
 
271
- ### Generic Message Interfaces (Zero-Boxing for Structs)
297
+ ### "What if I want custom constructor logic?"
272
298
 
273
- **For performance-critical code**, implement the generic interfaces directly:
299
+ Keep the attributes and add a factory/helper so you still benefit from the generated constructor:
274
300
 
275
301
  ```csharp
276
- using DxMessaging.Core.Messages;
277
-
278
- public readonly struct Heal : ITargetedMessage<Heal>
302
+ [DxUntargetedMessage]
303
+ [DxAutoConstructor]
304
+ public readonly partial struct ComplexMessage
279
305
  {
280
- public readonly int amount;
306
+ public readonly int value;
281
307
 
282
- public Heal(int amount)
308
+ public static ComplexMessage FromRaw(int rawValue)
283
309
  {
284
- this.amount = amount;
310
+ int clamped = Math.Clamp(rawValue, 0, 100);
311
+ return new ComplexMessage(clamped);
285
312
  }
286
-
287
- // Required for IMessage
288
- public Type MessageType => typeof(Heal);
289
313
  }
290
314
  ```
291
315
 
292
- #### Why use generics?
316
+ If you truly must write a custom constructor, drop `[DxAutoConstructor]` for that type but keep the `[DxUntargetedMessage]`/`[DxTargetedMessage]` attribute so the interface plumbing stays consistent.
293
317
 
294
- - Avoids boxing structs (important for performance)
295
- - Provides stable `MessageType` without `GetType()` calls
296
- - Same performance as attribute-based approach
318
+ ### "Can I mix attribute-based and manual messages?"
297
319
 
298
- ##### When to use
320
+ Yes. Attribute-driven messages happily coexist with string messages and any manual implementations you already have. You can migrate gradually by converting one message at a time:
299
321
 
300
- - Hot path messages (sent/received every frame)
301
- - Very large structs where boxing matters
302
- - When you want explicit control
303
-
304
- ###### When to use attributes
322
+ ```csharp
323
+ [DxUntargetedMessage]
324
+ [DxAutoConstructor]
325
+ public readonly partial struct MessageA
326
+ {
327
+ public readonly int value;
328
+ }
305
329
 
306
- - 99% of cases (they generate the same code!)
307
- - Cleaner, less boilerplate
308
- - Easier to maintain
330
+ // Existing manual message types keep working alongside attribute-driven ones.
331
+ ```
309
332
 
310
333
  ## Extension Methods (Emit Helpers)
311
334
 
@@ -355,7 +378,7 @@ using DxMessaging.Core.MessageBus;
355
378
 
356
379
  // Create isolated bus
357
380
  var testBus = new MessageBus();
358
- var handler = new MessageHandler(new InstanceId(1)) { active = true };
381
+ var handler = new MessageHandler(new InstanceId(1), testBus) { active = true };
359
382
  var token = MessageRegistrationToken.Create(handler, testBus);
360
383
 
361
384
  // Register on isolated bus
@@ -549,50 +572,42 @@ public readonly partial struct MyMessage : IUntargetedMessage<MyMessage>
549
572
 
550
573
  ### "What if I want custom constructor logic?"
551
574
 
552
- Use manual implementation:
575
+ Keep the attributes and wrap the generated constructor with a helper so you can inject custom logic without losing the source-generated plumbing:
553
576
 
554
577
  ```csharp
555
- public readonly struct ComplexMessage : IUntargetedMessage<ComplexMessage>
578
+ [DxUntargetedMessage]
579
+ [DxAutoConstructor]
580
+ public readonly partial struct ComplexMessage
556
581
  {
557
582
  public readonly int value;
558
583
 
559
- public ComplexMessage(int rawValue)
584
+ public static ComplexMessage FromRaw(int rawValue)
560
585
  {
561
- // Custom logic
562
- value = Math.Clamp(rawValue, 0, 100);
586
+ int clamped = Math.Clamp(rawValue, 0, 100);
587
+ return new ComplexMessage(clamped);
563
588
  }
564
-
565
- public Type MessageType => typeof(ComplexMessage);
566
589
  }
567
590
  ```
568
591
 
592
+ If you truly need to hand-craft the constructor, drop `[DxAutoConstructor]` for that specific type but keep the `[DxUntargetedMessage]`/`[DxTargetedMessage]` attribute so the interface implementation is still generated.
593
+
569
594
  ### "Do attributes affect runtime performance?"
570
595
 
571
596
  **No!** Source generation happens at **compile time**. Generated code is identical to hand-written code. Zero runtime overhead.
572
597
 
573
598
  ### "Can I mix attributes and manual implementation?"
574
599
 
575
- **Not on the same type**, but you can have:
576
-
577
- - Some messages using attributes
578
- - Other messages using manual implementation
579
- - Mix and match across your codebase
600
+ Yes. Attribute-driven messages happily coexist with any legacy manual messages or string messages you already emit. Convert types gradually—one message at a time:
580
601
 
581
602
  ```csharp
582
- // Message A: Attributes
583
603
  [DxUntargetedMessage]
584
604
  [DxAutoConstructor]
585
- public readonly partial struct MessageA { public readonly int value; }
586
-
587
- // Message B: Manual
588
- public readonly struct MessageB : IUntargetedMessage<MessageB>
605
+ public readonly partial struct MessageA
589
606
  {
590
607
  public readonly int value;
591
- public MessageB(int value) { this.value = value; }
592
- public Type MessageType => typeof(MessageB);
593
608
  }
594
609
 
595
- // Both work perfectly together!
610
+ // Existing manual messages keep working alongside attribute-driven ones.
596
611
  ```
597
612
 
598
613
  ## Troubleshooting Source Generators
@@ -609,7 +624,7 @@ public readonly struct MessageB : IUntargetedMessage<MessageB>
609
624
  ##### Fix
610
625
 
611
626
  ```csharp
612
- // ❌ Missing partial
627
+ // ❌ Missing partial, will not compile
613
628
  [DxAutoConstructor]
614
629
  public readonly struct MyMsg { }
615
630
 
package/Docs/Index.md CHANGED
@@ -4,28 +4,18 @@
4
4
 
5
5
  ## Visual Documentation Map
6
6
 
7
- ```text
8
- ┌─────────────────┐
9
- START HERE
10
- │ Visual Guide │
11
- │ (5 minutes) │
12
- └────────┬────────┘
13
-
14
- ┌──────────────────┼──────────────────┐
15
- │ │ │
16
- ┌─────▼──────┐ ┌─────▼──────┐ ┌─────▼──────┐
17
- │ Quick │ │ Getting │ │ Overview │
18
- │ Start │ │ Started │ │ │
19
- │ (5 min) │ │ (10 min) │ │ (5 min) │
20
- └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
21
- │ │ │
22
- └──────────────────┼──────────────────┘
23
-
24
- ┌──────▼──────┐
25
- │ Patterns │
26
- │ & Samples │
27
- │ (Hands-on!) │
28
- └─────────────┘
7
+ ```mermaid
8
+ graph TD
9
+ Start[START HERE<br/>Visual Guide<br/>5 minutes]
10
+ Start --> Quick[Quick Start<br/>5 min]
11
+ Start --> Getting[Getting Started<br/>10 min]
12
+ Start --> Overview[Overview<br/>5 min]
13
+ Quick --> Patterns[Patterns & Samples<br/>Hands-on!]
14
+ Getting --> Patterns
15
+ Overview --> Patterns
16
+
17
+ style Start fill:#91d5ff,stroke:#096dd9,stroke-width:3px,color:#000
18
+ style Patterns fill:#95de64,stroke:#237804,stroke-width:2px,color:#000
29
19
  ```
30
20
 
31
21
  ## Table of Contents
@@ -108,6 +98,8 @@
108
98
  ### Tools & Utilities
109
99
 
110
100
  - **[Helpers](Helpers.md)** — Source generators, attributes, extensions
101
+ - **[Message Bus Providers](MessageBusProviders.md)** — Provider system and MessageBusProviderHandle for flexible bus configuration
102
+ - **[Runtime Configuration](RuntimeConfiguration.md)** — Setting message buses at runtime, re-binding registrations
111
103
  - **[Emit Shorthands](EmitShorthands.md)** — `Emit`/`EmitAt`/`EmitFrom` usage and pitfalls
112
104
  - **[String Messages](StringMessages.md)** — Prototyping and debugging
113
105
  - **[Compatibility](Compatibility.md)** — Unity versions and render pipelines
@@ -159,6 +151,9 @@ From [Common Patterns](Patterns.md):
159
151
  - **Debug message flow** → Use [Diagnostics](Diagnostics.md)
160
152
  - **Optimize performance** → Read [Performance Tips](DesignAndArchitecture.md#performance-tuning-tips)
161
153
  - **Isolate tests** → Create [Local Bus Islands](DesignAndArchitecture.md#local-bus-islands)
154
+ - **Use dependency injection** → [DxMessaging + Zenject](Integrations/Zenject.md), [DxMessaging + VContainer](Integrations/VContainer.md), [DxMessaging + Reflex](Integrations/Reflex.md)
155
+ - **Configure buses at runtime** → See [Runtime Configuration](RuntimeConfiguration.md)
156
+ - **Use message bus providers** → Learn [Message Bus Providers](MessageBusProviders.md)
162
157
 
163
158
  ## 📊 Visual: Message Pipeline
164
159
 
@@ -169,9 +164,9 @@ flowchart LR
169
164
  P[Producer] --> I[Interceptors<br/>validate/mutate/cancel]
170
165
  I --> H[Handlers<br/>main logic by priority]
171
166
  H --> PP[Post-Processors<br/>analytics/logging]
172
- style I fill:#fff4e5,stroke:#f0b429
173
- style H fill:#e6f7ff,stroke:#1890ff
174
- style PP fill:#eef7ee,stroke:#52c41a
167
+ style I fill:#ffe7ba,stroke:#d48806,stroke-width:2px,color:#000
168
+ style H fill:#91d5ff,stroke:#096dd9,stroke-width:2px,color:#000
169
+ style PP fill:#b7eb8f,stroke:#389e0d,stroke-width:2px,color:#000
175
170
  ```
176
171
 
177
172
  ## 🎓 Learning Resources
@@ -269,6 +264,14 @@ From [Comparisons](Comparisons.md):
269
264
  - [FAQ](FAQ.md)
270
265
  - [Troubleshooting](Troubleshooting.md)
271
266
 
267
+ ### Dependency Injection
268
+
269
+ - [Runtime Configuration](RuntimeConfiguration.md) — Setting and overriding message buses, re-binding registrations
270
+ - [Message Bus Providers](MessageBusProviders.md) — Provider system and MessageBusProviderHandle
271
+ - [DxMessaging + Zenject](Integrations/Zenject.md) — Zenject integration guide
272
+ - [DxMessaging + VContainer](Integrations/VContainer.md) — VContainer integration guide
273
+ - [DxMessaging + Reflex](Integrations/Reflex.md) — Reflex integration guide
274
+
272
275
  ### Miscellaneous
273
276
 
274
277
  - [String Messages](StringMessages.md)
package/Docs/Install.md CHANGED
@@ -2,34 +2,57 @@
2
2
 
3
3
  This page helps you install DxMessaging into a Unity 2021.3+ project using the Unity Package Manager (UPM).
4
4
 
5
- Fast path
5
+ ## Methods
6
+
7
+ ### Fast path
6
8
 
7
9
  - Unity Package Manager > Add package from git URL...
8
10
  - Paste:
9
11
 
10
12
  ```text
11
- https://github.com/wallstop/DxMessaging.git?path=/Packages/com.wallstop-studios.dxmessaging
13
+ https://github.com/wallstop/DxMessaging.git
12
14
  ```
13
15
 
14
16
  - Click Add. Unity imports the package and its analyzers/generators.
15
17
 
16
- Manifest.json (alternative)
18
+ ### To Install as Unity Package
19
+
20
+ 1. Open Unity Package Manager
21
+ 1. (Optional) Enable Pre-release packages to get the latest, cutting-edge builds
22
+ 1. Open the Advanced Package Settings
23
+ 1. Add an entry for a new "Scoped Registry"
24
+ - Name: `NPM`
25
+ - URL: `https://registry.npmjs.org`
26
+ - Scope(s): `com.wallstop-studios.dxmessaging`
27
+ 1. Resolve the latest `DxMessaging`
28
+
29
+ ⭐ Bonus of Unity Package way - Unity will tell you of version updates
30
+
31
+ ### From Releases
32
+
33
+ Check out the latest [Releases](https://github.com/wallstop/DxMessaging/releases) to grab the Unity Package and import to your project.
34
+
35
+ ### From Source
36
+
37
+ Grab a copy of this repo (either `git clone` [this repo](https://github.com/wallstop/DxMessaging) or [download a zip of the source](https://github.com/wallstop/DxMessaging/archive/refs/heads/master.zip)) and copy the contents to your project's `Assets` directory.
38
+
39
+ ### Manual - Manifest.json (alternative, not recommended)
17
40
 
18
41
  - Open your project’s `Packages/manifest.json` and add:
19
42
 
20
43
  ```json
21
44
  {
22
45
  "dependencies": {
23
- "com.wallstop-studios.dxmessaging": "https://github.com/wallstop/DxMessaging.git?path=/Packages/com.wallstop-studios.dxmessaging"
46
+ "com.wallstop-studios.dxmessaging": "https://github.com/wallstop/DxMessaging.git"
24
47
  }
25
48
  }
26
49
  ```
27
50
 
28
- Minimum requirements
51
+ ## Minimum requirements
29
52
 
30
53
  - Unity 2021.3+ (LTS recommended). See [Compatibility](Compatibility.md) for Unity × Render Pipeline support (Built‑In, URP, HDRP).
31
54
 
32
- After install
55
+ ## After install
33
56
 
34
57
  - In your project, create a GameObject and add `MessagingComponent` to start sending/receiving.
35
58
  - Optional: enable diagnostics in Editor from the MessagingComponent inspector to see live emissions.