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
@@ -0,0 +1,496 @@
1
+ # Message Bus Providers
2
+
3
+ DxMessaging provides a flexible provider system that lets you configure which message bus drives your components. This works both at design time (with ScriptableObject providers) and at runtime (with provider handles).
4
+
5
+ This guide covers:
6
+
7
+ - The `IMessageBusProvider` interface
8
+ - Built-in ScriptableObject providers
9
+ - The `MessageBusProviderHandle` system
10
+ - How to create custom providers
11
+ - Practical usage patterns
12
+
13
+ ---
14
+
15
+ ## Table of Contents
16
+
17
+ - [Overview](#overview)
18
+ - [IMessageBusProvider Interface](#imessagebusprovider-interface)
19
+ - [Built-in Providers](#built-in-providers)
20
+ - [Current Global Message Bus Provider](#current-global-message-bus-provider)
21
+ - [Initial Global Message Bus Provider](#initial-global-message-bus-provider)
22
+ - [MessageBusProviderHandle](#messagebusproviderhandle)
23
+ - [Using Providers with Components](#using-providers-with-components)
24
+ - [Creating Custom Providers](#creating-custom-providers)
25
+ - [Common Patterns](#common-patterns)
26
+
27
+ ---
28
+
29
+ ## Overview
30
+
31
+ Providers abstract away the details of how a message bus is resolved. This lets you:
32
+
33
+ - **Swap buses at design time** — Change a ScriptableObject reference without modifying code
34
+ - **Integrate with DI containers** — Resolve buses from your container
35
+ - **Support runtime reconfiguration** — Change which bus a component uses dynamically
36
+ - **Isolate scenes or features** — Use different buses for different parts of your game
37
+
38
+ If you're using the default global bus everywhere, you probably don't need providers. They're most useful when you need flexibility or are integrating with DI frameworks.
39
+
40
+ ---
41
+
42
+ ## IMessageBusProvider Interface
43
+
44
+ All providers implement this simple interface:
45
+
46
+ ```csharp
47
+ public interface IMessageBusProvider
48
+ {
49
+ IMessageBus Resolve();
50
+ }
51
+ ```
52
+
53
+ When a component needs a bus, it calls `Resolve()` on its provider. The provider returns the appropriate bus instance.
54
+
55
+ **Key insight:** By abstracting bus resolution behind this interface, components don't need to know whether they're using the global bus, a container-managed bus, or something completely custom.
56
+
57
+ ---
58
+
59
+ ## Built-in Providers
60
+
61
+ DxMessaging ships with two ScriptableObject-based providers. These are assets you can create in the editor and reference in your scenes.
62
+
63
+ ### Current Global Message Bus Provider
64
+
65
+ `CurrentGlobalMessageBusProvider` returns whatever bus is currently set as the global bus via `MessageHandler.MessageBus`. If you override the global bus at runtime, this provider reflects that change.
66
+
67
+ #### Creating the asset
68
+
69
+ Right-click in the Project window:
70
+
71
+ ```text
72
+ Create > Wallstop Studios > DxMessaging > Message Bus Providers > Current Global Message Bus
73
+ ```
74
+
75
+ #### When to use this
76
+
77
+ - When you want components to follow the global bus, even if it changes
78
+ - In DI scenarios where the global bus is replaced during bootstrap
79
+ - For components that should always use the "active" bus
80
+
81
+ #### Example
82
+
83
+ ```csharp
84
+ using DxMessaging.Core.MessageBus;
85
+ using DxMessaging.Unity;
86
+ using UnityEngine;
87
+
88
+ [RequireComponent(typeof(MessagingComponent))]
89
+ public sealed class MessagingComponentConfigurator : MonoBehaviour
90
+ {
91
+ [SerializeField]
92
+ private CurrentGlobalMessageBusProvider provider;
93
+
94
+ private void Awake()
95
+ {
96
+ MessagingComponent component = GetComponent<MessagingComponent>();
97
+ component.Configure(provider, MessageBusRebindMode.RebindActive);
98
+ }
99
+ }
100
+ ```
101
+
102
+ ### Initial Global Message Bus Provider
103
+
104
+ `InitialGlobalMessageBusProvider` always returns the original startup bus that was created during static initialization. It ignores any calls to `SetGlobalMessageBus()` or `OverrideGlobalMessageBus()`.
105
+
106
+ #### Creating the asset
107
+
108
+ Right-click in the Project window:
109
+
110
+ ```text
111
+ Create > Wallstop Studios > DxMessaging > Message Bus Providers > Initial Global Message Bus
112
+ ```
113
+
114
+ #### When to use this
115
+
116
+ - In diagnostic tools that need a stable reference point
117
+ - When testing with temporary bus overrides but need access to the original
118
+ - For debugging scenarios where you want to compare against the startup bus
119
+
120
+ #### Example
121
+
122
+ ```csharp
123
+ using DxMessaging.Core;
124
+ using DxMessaging.Core.MessageBus;
125
+ using UnityEngine;
126
+
127
+ public class DiagnosticLogger : MonoBehaviour
128
+ {
129
+ [SerializeField]
130
+ private InitialGlobalMessageBusProvider initialProvider;
131
+
132
+ private void Start()
133
+ {
134
+ // Always logs to the original bus, even if global bus is overridden
135
+ IMessageBus startupBus = initialProvider.Resolve();
136
+
137
+ // Can compare with current global bus
138
+ bool busWasReplaced = startupBus != MessageHandler.MessageBus;
139
+ Debug.Log($"Bus replaced: {busWasReplaced}");
140
+ }
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## MessageBusProviderHandle
147
+
148
+ `MessageBusProviderHandle` is a serializable struct that can reference either:
149
+
150
+ - A ScriptableObject provider (design-time configuration)
151
+ - A runtime provider instance (runtime configuration)
152
+
153
+ This gives you the best of both worlds: editor-friendly assets and runtime flexibility.
154
+
155
+ ### Key Methods
156
+
157
+ ```csharp
158
+ // Create from a runtime provider
159
+ MessageBusProviderHandle handle = MessageBusProviderHandle.FromProvider(myProvider);
160
+
161
+ // Associate a runtime provider with an existing handle
162
+ handle = handle.WithRuntimeProvider(myRuntimeProvider);
163
+
164
+ // Resolve the provider (runtime takes precedence over asset)
165
+ if (handle.TryGetProvider(out IMessageBusProvider provider))
166
+ {
167
+ IMessageBus bus = provider.Resolve();
168
+ }
169
+
170
+ // Or resolve the bus directly
171
+ IMessageBus bus = handle.ResolveBus();
172
+ ```
173
+
174
+ ### How It Works
175
+
176
+ The handle has two fields:
177
+
178
+ 1. `Provider` — A serialized reference to a ScriptableObject provider (visible in Inspector)
179
+ 1. A runtime provider instance (not serialized)
180
+
181
+ When you call `TryGetProvider()` or `ResolveBus()`, it checks:
182
+
183
+ 1. Is there a runtime provider? Use that first.
184
+ 1. Otherwise, use the serialized ScriptableObject provider.
185
+ 1. If neither exists, return null or the global default.
186
+
187
+ **Why this matters:** You can design your prefabs with ScriptableObject references, then override them at runtime with DI-provided buses. No code changes needed.
188
+
189
+ ### Example: Design Time Configuration
190
+
191
+ ```csharp
192
+ using DxMessaging.Unity;
193
+ using UnityEngine;
194
+
195
+ public class PlayerController : MessageAwareComponent
196
+ {
197
+ [SerializeField]
198
+ private MessageBusProviderHandle providerHandle;
199
+
200
+ protected override void Awake()
201
+ {
202
+ // Configure with the handle before base.Awake()
203
+ if (providerHandle.TryGetProvider(out var provider))
204
+ {
205
+ ConfigureMessageBus(provider, MessageBusRebindMode.RebindActive);
206
+ }
207
+
208
+ base.Awake();
209
+ }
210
+ }
211
+ ```
212
+
213
+ In the Inspector, you can drag a `CurrentGlobalMessageBusProvider` or `InitialGlobalMessageBusProvider` asset onto the `providerHandle` field.
214
+
215
+ ### Example: Runtime Override
216
+
217
+ ```csharp
218
+ using DxMessaging.Core.MessageBus;
219
+ using DxMessaging.Unity;
220
+
221
+ public class DynamicConfigurator
222
+ {
223
+ public void ConfigureWithRuntimeBus(MessageAwareComponent component, IMessageBus runtimeBus)
224
+ {
225
+ // Create a runtime provider
226
+ var provider = new RuntimeMessageBusProvider(runtimeBus);
227
+
228
+ // Wrap it in a handle
229
+ var handle = MessageBusProviderHandle.FromProvider(provider);
230
+
231
+ // Configure the component
232
+ component.ConfigureMessageBus(handle, MessageBusRebindMode.RebindActive);
233
+ }
234
+ }
235
+
236
+ // Simple runtime provider implementation
237
+ public class RuntimeMessageBusProvider : IMessageBusProvider
238
+ {
239
+ private readonly IMessageBus _bus;
240
+
241
+ public RuntimeMessageBusProvider(IMessageBus bus)
242
+ {
243
+ _bus = bus;
244
+ }
245
+
246
+ public IMessageBus Resolve() => _bus;
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Using Providers with Components
253
+
254
+ ### MessagingComponent
255
+
256
+ `MessagingComponent` has three `Configure()` overloads:
257
+
258
+ ```csharp
259
+ // Direct bus reference
260
+ component.Configure(messageBus, MessageBusRebindMode.RebindActive);
261
+
262
+ // Provider interface
263
+ component.Configure(provider, MessageBusRebindMode.RebindActive);
264
+
265
+ // Provider handle (design-time or runtime)
266
+ component.Configure(providerHandle, MessageBusRebindMode.RebindActive);
267
+ ```
268
+
269
+ ### MessageAwareComponent
270
+
271
+ `MessageAwareComponent` exposes `ConfigureMessageBus()` with the same three overloads:
272
+
273
+ ```csharp
274
+ // Direct bus
275
+ ConfigureMessageBus(messageBus, MessageBusRebindMode.RebindActive);
276
+
277
+ // Provider
278
+ ConfigureMessageBus(provider, MessageBusRebindMode.RebindActive);
279
+
280
+ // Handle
281
+ ConfigureMessageBus(providerHandle, MessageBusRebindMode.RebindActive);
282
+ ```
283
+
284
+ **Best practice:** Call `ConfigureMessageBus()` in `Awake()` before calling `base.Awake()` to ensure the bus is set before message handlers are registered.
285
+
286
+ ### MessagingComponentInstaller
287
+
288
+ `MessagingComponentInstaller` configures all `MessagingComponent` descendants in a hierarchy:
289
+
290
+ ```csharp
291
+ using DxMessaging.Core.MessageBus;
292
+ using DxMessaging.Unity;
293
+ using UnityEngine;
294
+
295
+ public class SceneSetup : MonoBehaviour
296
+ {
297
+ [SerializeField]
298
+ private MessagingComponentInstaller installer;
299
+
300
+ [SerializeField]
301
+ private CurrentGlobalMessageBusProvider provider;
302
+
303
+ private void Awake()
304
+ {
305
+ // Configure installer with provider
306
+ installer.SetProvider(MessageBusProviderHandle.FromProvider(provider));
307
+
308
+ // Apply to all child MessagingComponents
309
+ installer.ApplyConfiguration();
310
+ }
311
+ }
312
+ ```
313
+
314
+ This is useful when you want to configure an entire prefab hierarchy or scene section with a single provider.
315
+
316
+ ---
317
+
318
+ ## Creating Custom Providers
319
+
320
+ You can create your own providers for advanced scenarios:
321
+
322
+ ### Example: Container-Managed Provider
323
+
324
+ ```csharp
325
+ using DxMessaging.Core.MessageBus;
326
+
327
+ public class ContainerMessageBusProvider : IMessageBusProvider
328
+ {
329
+ private readonly IDependencyContainer _container;
330
+
331
+ public ContainerMessageBusProvider(IDependencyContainer container)
332
+ {
333
+ _container = container;
334
+ }
335
+
336
+ public IMessageBus Resolve()
337
+ {
338
+ // Resolve from container each time
339
+ return _container.Resolve<IMessageBus>();
340
+ }
341
+ }
342
+ ```
343
+
344
+ ### Example: ScriptableObject Provider for Specific Bus
345
+
346
+ ```csharp
347
+ using DxMessaging.Core.MessageBus;
348
+ using UnityEngine;
349
+
350
+ [CreateAssetMenu(menuName = "Game/Messaging/Custom Bus Provider")]
351
+ public class CustomBusProvider : ScriptableObject, IMessageBusProvider
352
+ {
353
+ [SerializeField]
354
+ private bool useTestBus;
355
+
356
+ private static IMessageBus _testBus;
357
+ private static IMessageBus _productionBus;
358
+
359
+ public IMessageBus Resolve()
360
+ {
361
+ if (useTestBus)
362
+ {
363
+ return _testBus ??= new MessageBus();
364
+ }
365
+ return _productionBus ??= new MessageBus();
366
+ }
367
+ }
368
+ ```
369
+
370
+ ### Example: Lazy-Initialized Provider
371
+
372
+ ```csharp
373
+ using DxMessaging.Core.MessageBus;
374
+
375
+ public class LazyMessageBusProvider : IMessageBusProvider
376
+ {
377
+ private IMessageBus _cachedBus;
378
+
379
+ public IMessageBus Resolve()
380
+ {
381
+ // Only create the bus when first requested
382
+ return _cachedBus ??= new MessageBus();
383
+ }
384
+ }
385
+ ```
386
+
387
+ ---
388
+
389
+ ## Common Patterns
390
+
391
+ ### Pattern 1: Design-Time Configuration
392
+
393
+ Set up providers in the editor, no code needed:
394
+
395
+ 1. Create a `CurrentGlobalMessageBusProvider` asset in your project
396
+ 1. Add a `MessagingComponent` to your prefab
397
+ 1. Add a `MessagingComponentConfigurator` script that references the provider
398
+ 1. In Awake, call `component.Configure(provider, ...)`
399
+
400
+ This lets designers swap providers without touching code.
401
+
402
+ ### Pattern 2: DI Container Integration
403
+
404
+ Use a provider to resolve buses from your container:
405
+
406
+ ```csharp
407
+ // In your DI installer
408
+ container.RegisterInstance<IMessageBus>(new MessageBus());
409
+
410
+ // In a bootstrap script
411
+ var provider = new ContainerMessageBusProvider(container);
412
+ MessageHandler.SetGlobalMessageBus(provider.Resolve());
413
+
414
+ // Now all components use the container bus
415
+ ```
416
+
417
+ ### Pattern 3: Scene-Scoped Buses
418
+
419
+ Create a provider that returns a scene-specific bus:
420
+
421
+ ```csharp
422
+ public class SceneMessageBusManager : MonoBehaviour
423
+ {
424
+ private IMessageBus _sceneBus;
425
+
426
+ private void Awake()
427
+ {
428
+ // Create scene-local bus
429
+ _sceneBus = new MessageBus();
430
+
431
+ // Configure all components in this scene
432
+ var components = GetComponentsInChildren<MessagingComponent>();
433
+ var provider = new RuntimeMessageBusProvider(_sceneBus);
434
+
435
+ foreach (var component in components)
436
+ {
437
+ component.Configure(provider, MessageBusRebindMode.RebindActive);
438
+ }
439
+ }
440
+ }
441
+ ```
442
+
443
+ Messages sent in this scene stay in this scene.
444
+
445
+ ### Pattern 4: Runtime Provider Override
446
+
447
+ Start with a design-time provider, override at runtime:
448
+
449
+ ```csharp
450
+ public class RuntimeReconfiguration : MonoBehaviour
451
+ {
452
+ [SerializeField]
453
+ private MessageAwareComponent component;
454
+
455
+ [SerializeField]
456
+ private MessageBusProviderHandle designTimeHandle; // Set in Inspector
457
+
458
+ private void Start()
459
+ {
460
+ // Use design-time provider initially
461
+ component.ConfigureMessageBus(designTimeHandle, MessageBusRebindMode.RebindActive);
462
+ }
463
+
464
+ public void SwitchToRuntimeBus(IMessageBus runtimeBus)
465
+ {
466
+ // Override with runtime provider
467
+ var runtimeProvider = new RuntimeMessageBusProvider(runtimeBus);
468
+ var handle = MessageBusProviderHandle.FromProvider(runtimeProvider);
469
+ component.ConfigureMessageBus(handle, MessageBusRebindMode.RebindActive);
470
+ }
471
+ }
472
+ ```
473
+
474
+ ---
475
+
476
+ ## Quick Reference
477
+
478
+ | Type | Purpose | Use Case |
479
+ | -------------------------------------- | --------------------------------------------- | --------------------------------- |
480
+ | `IMessageBusProvider` | Interface for bus resolution | Create custom providers |
481
+ | `CurrentGlobalMessageBusProvider` | ScriptableObject returning current global bus | Follow the active global bus |
482
+ | `InitialGlobalMessageBusProvider` | ScriptableObject returning startup bus | Diagnostics, stable reference |
483
+ | `MessageBusProviderHandle` | Serializable wrapper for providers | Design-time + runtime flexibility |
484
+ | `handle.FromProvider(provider)` | Create handle from runtime provider | Runtime configuration |
485
+ | `handle.WithRuntimeProvider(provider)` | Add runtime provider to handle | Override design-time config |
486
+ | `handle.TryGetProvider(out provider)` | Resolve provider from handle | Get the actual provider |
487
+ | `handle.ResolveBus()` | Resolve bus directly | Shortcut to get bus |
488
+
489
+ ---
490
+
491
+ ## See Also
492
+
493
+ - **[Runtime Configuration](RuntimeConfiguration.md)** — Setting and overriding global buses, re-binding registrations
494
+ - **[DI Integration Guides](Integrations/)** — Zenject, VContainer, and Reflex integration patterns
495
+ - **[Unity Integration](UnityIntegration.md)** — MessagingComponent and MessageAwareComponent deep dive
496
+ - **[Back to Documentation Hub](Index.md)** — Browse all docs
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: 647a230de59ff1943b04087a065ea75c
3
+ TextScriptImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant:
@@ -12,6 +12,33 @@ This guide introduces the three message categories in DxMessaging with concepts,
12
12
  - Targeted: directed at one recipient (e.g., heal Player by 10).
13
13
  - Broadcast: emitted from a source for anyone to observe (e.g., Enemy took 5 damage).
14
14
 
15
+ ### Quick Decision Guide
16
+
17
+ ```mermaid
18
+ flowchart TD
19
+ Start([Choose Message Type])
20
+
21
+ Start --> Q1{Is it a global<br/>announcement?}
22
+
23
+ Q1 -->|Yes<br/>e.g., game paused,<br/>settings changed| Untargeted[✅ Use UNTARGETED<br/>Everyone listens]
24
+
25
+ Q1 -->|No| Q2{Are you commanding<br/>a specific entity?}
26
+
27
+ Q2 -->|Yes<br/>e.g., heal Player,<br/>open Chest #3| Targeted[✅ Use TARGETED<br/>One recipient]
28
+
29
+ Q2 -->|No| Q3{Is an entity announcing<br/>something happened?}
30
+
31
+ Q3 -->|Yes<br/>e.g., Enemy died,<br/>Chest opened| Broadcast[✅ Use BROADCAST<br/>Anyone can observe]
32
+
33
+ Q3 -->|No| Rethink[🤔 Rethink your<br/>message design]
34
+
35
+ style Untargeted fill:#91d5ff,stroke:#096dd9,stroke-width:3px,color:#000
36
+ style Targeted fill:#ffd591,stroke:#d46b08,stroke-width:3px,color:#000
37
+ style Broadcast fill:#95de64,stroke:#237804,stroke-width:3px,color:#000
38
+ style Rethink fill:#ffa39e,stroke:#cf1322,stroke-width:2px,color:#000
39
+ style Start fill:#f0f0f0,stroke:#595959,stroke-width:2px,color:#000
40
+ ```
41
+
15
42
  ## Untargeted Messages
16
43
 
17
44
  - Use for cross‑cutting notifications: settings changed, scene loaded, world regenerated.
@@ -431,6 +431,51 @@ Phase them out gradually:
431
431
  1. Migrate listeners
432
432
  1. Remove references in next refactor pass
433
433
 
434
+ ### Adopt the DI Registration Builder
435
+
436
+ Once the bus/provider abstractions are in place, wire listeners through the registration builder instead of hand-rolling handler lifecycles. Benefits:
437
+
438
+ - Container-managed lifetimes (`IDisposable`, `IInitializable`, `IStartable`, etc.) automatically enable/disable registrations.
439
+ - Centralises diagnostics toggles and message bus selection.
440
+ - Keeps MonoBehaviours and pure C# services on the same path.
441
+
442
+ ```csharp
443
+ public sealed class InventoryService : IStartable, IDisposable
444
+ {
445
+ private readonly MessageRegistrationLease lease;
446
+
447
+ public InventoryService(IMessageRegistrationBuilder registrationBuilder)
448
+ {
449
+ lease = registrationBuilder.Build(new MessageRegistrationBuildOptions
450
+ {
451
+ Configure = token =>
452
+ {
453
+ _ = token.RegisterUntargeted<InventoryChanged>(OnInventoryChanged);
454
+ }
455
+ });
456
+ }
457
+
458
+ public void Start()
459
+ {
460
+ lease.Activate();
461
+ }
462
+
463
+ public void Dispose()
464
+ {
465
+ lease.Dispose();
466
+ }
467
+
468
+ private static void OnInventoryChanged(ref InventoryChanged message)
469
+ {
470
+ // respond to updates
471
+ }
472
+ }
473
+ ```
474
+
475
+ - **Unity scene code:** Call `MessagingComponent.CreateRegistrationBuilder()` during dependency injection and share the lease across helper services or pooled objects.
476
+ - **Container shims:** Define `ZENJECT_PRESENT`, `VCONTAINER_PRESENT`, or `REFLEX_PRESENT` to enable the built-in installers/extensions that register the builder automatically when those frameworks are present.
477
+ - **Tests:** Prefer the builder to create isolated tokens tied to the test fixture lifecycle.
478
+
434
479
  ### "Should we migrate tests?"
435
480
 
436
481
  Yes! Tests benefit from isolated message buses: