com.wallstop-studios.dxmessaging 2.0.0 → 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 (174) 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 +1 -1
  14. package/Docs/Index.md +28 -25
  15. package/Docs/Install.md +29 -6
  16. package/Docs/Integrations/Reflex.md +292 -0
  17. package/Docs/Integrations/Reflex.md.meta +7 -0
  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/RuntimeConfiguration.md +407 -0
  33. package/Docs/RuntimeConfiguration.md.meta +7 -0
  34. package/Docs/UnityIntegration.md +3 -1
  35. package/Docs/VisualGuide.md +206 -157
  36. package/Editor/CustomEditors/MessagingComponentEditor.cs +15 -6
  37. package/README.md +148 -26
  38. package/Runtime/AssemblyInfo.cs +4 -0
  39. package/Runtime/Core/Extensions/MessageBusExtensions.cs +253 -0
  40. package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -0
  41. package/Runtime/Core/Extensions/MessageExtensions.cs +137 -89
  42. package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs +23 -0
  43. package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -0
  44. package/Runtime/Core/MessageBus/IMessageBusProvider.cs +14 -0
  45. package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -0
  46. package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +18 -0
  47. package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -0
  48. package/Runtime/Core/MessageBus/MessageBusRebindMode.cs +26 -0
  49. package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -0
  50. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +383 -0
  51. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -0
  52. package/Runtime/Core/MessageHandler.cs +198 -27
  53. package/Runtime/Core/MessageRegistrationToken.cs +67 -25
  54. package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs +31 -0
  55. package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +12 -0
  56. package/Runtime/Unity/InitialGlobalMessageBusProvider.cs +38 -0
  57. package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +12 -0
  58. package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs +11 -0
  59. package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +3 -0
  60. package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +73 -0
  61. package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +11 -0
  62. package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef +20 -0
  63. package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef.meta +7 -0
  64. package/Runtime/Unity/Integrations/Reflex.meta +8 -0
  65. package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs +11 -0
  66. package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +3 -0
  67. package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +46 -0
  68. package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +11 -0
  69. package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef +30 -0
  70. package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef.meta +7 -0
  71. package/Runtime/Unity/Integrations/VContainer.meta +8 -0
  72. package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs +11 -0
  73. package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +3 -0
  74. package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef +30 -0
  75. package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef.meta +7 -0
  76. package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +55 -0
  77. package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +11 -0
  78. package/Runtime/Unity/Integrations/Zenject.meta +8 -0
  79. package/Runtime/Unity/Integrations.meta +8 -0
  80. package/Runtime/Unity/MessageAwareComponent.cs +102 -0
  81. package/Runtime/Unity/MessageBusProviderHandle.cs +97 -0
  82. package/Runtime/Unity/MessageBusProviderHandle.cs.meta +12 -0
  83. package/Runtime/Unity/MessagingComponent.cs +164 -2
  84. package/Runtime/Unity/MessagingComponentInstaller.cs +120 -0
  85. package/Runtime/Unity/MessagingComponentInstaller.cs.meta +12 -0
  86. package/Runtime/Unity/ScriptableMessageBusProvider.cs +14 -0
  87. package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +12 -0
  88. package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab +98 -0
  89. package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab.meta +7 -0
  90. package/Samples~/DI/Prefabs.meta +8 -0
  91. package/Samples~/DI/Providers/GlobalMessageBusProvider.asset +14 -0
  92. package/Samples~/DI/Providers/GlobalMessageBusProvider.asset.meta +8 -0
  93. package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset +14 -0
  94. package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset.meta +8 -0
  95. package/Samples~/DI/Providers.meta +8 -0
  96. package/Samples~/DI/README.md +51 -0
  97. package/Samples~/DI/README.md.meta +7 -0
  98. package/Samples~/DI/Reflex/SampleInstaller.cs +75 -0
  99. package/Samples~/DI/Reflex/SampleInstaller.cs.meta +11 -0
  100. package/Samples~/DI/Reflex.meta +8 -0
  101. package/Samples~/DI/VContainer/SampleLifetimeScope.cs +81 -0
  102. package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -0
  103. package/Samples~/DI/VContainer.meta +8 -0
  104. package/Samples~/DI/Zenject/SampleInstaller.cs +67 -0
  105. package/Samples~/DI/Zenject/SampleInstaller.cs.meta +11 -0
  106. package/Samples~/DI/Zenject.meta +8 -0
  107. package/Samples~/DI.meta +8 -0
  108. package/Samples~/Mini Combat/README.md +5 -7
  109. package/Samples~/Mini Combat/Walkthrough.md +18 -24
  110. package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs +12 -2
  111. package/Samples~/UI Buttons + Inspector/README.md.meta +7 -0
  112. package/Tests/Runtime/Benchmarks/BenchmarkSession.cs +444 -0
  113. package/Tests/Runtime/Benchmarks/BenchmarkSession.cs.meta +11 -0
  114. package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs +94 -0
  115. package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs.meta +11 -0
  116. package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs +395 -0
  117. package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs.meta +11 -0
  118. package/Tests/Runtime/Benchmarks/PerformanceTests.cs +77 -429
  119. package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs +142 -0
  120. package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs.meta +12 -0
  121. package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef +50 -0
  122. package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef.meta +7 -0
  123. package/Tests/Runtime/Core/DefaultBusFallbackTests.cs +333 -0
  124. package/Tests/Runtime/Core/DefaultBusFallbackTests.cs.meta +11 -0
  125. package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs +278 -0
  126. package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs.meta +11 -0
  127. package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs +289 -0
  128. package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs.meta +11 -0
  129. package/Tests/Runtime/Core/Extensions.meta +8 -0
  130. package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs +57 -0
  131. package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs.meta +11 -0
  132. package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs +219 -0
  133. package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs.meta +11 -0
  134. package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs +204 -0
  135. package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs.meta +11 -0
  136. package/Tests/Runtime/Core/MessagingTestBase.cs +4 -4
  137. package/Tests/Runtime/Core/NominalTests.cs +2 -2
  138. package/Tests/Runtime/Core/TypedShorthandTests.cs +2 -2
  139. package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs +1 -1
  140. package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +2 -4
  141. package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs +162 -0
  142. package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs.meta +11 -0
  143. package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset +16 -0
  144. package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset.meta +8 -0
  145. package/Tests/Runtime/Integrations/Reflex/Resources.meta +8 -0
  146. package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef +27 -0
  147. package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef.meta +7 -0
  148. package/Tests/Runtime/Integrations/Reflex.meta +8 -0
  149. package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs +140 -0
  150. package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs.meta +11 -0
  151. package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef +37 -0
  152. package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef.meta +7 -0
  153. package/Tests/Runtime/Integrations/VContainer.meta +8 -0
  154. package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef +37 -0
  155. package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef.meta +7 -0
  156. package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs +140 -0
  157. package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs.meta +11 -0
  158. package/Tests/Runtime/Integrations/Zenject.meta +8 -0
  159. package/Tests/Runtime/Integrations.meta +8 -0
  160. package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs +1 -1
  161. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +1 -1
  162. package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs +1 -1
  163. package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs +64 -0
  164. package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs.meta +12 -0
  165. package/Tests/Runtime/TestUtilities.meta +9 -0
  166. package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs +57 -0
  167. package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs.meta +11 -0
  168. package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs +107 -0
  169. package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs.meta +12 -0
  170. package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs +210 -0
  171. package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs.meta +12 -0
  172. package/Tests/Runtime/Unity.meta +9 -0
  173. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef +3 -1
  174. package/package.json +1 -1
@@ -0,0 +1,324 @@
1
+ # DxMessaging + VContainer
2
+
3
+ [← Back to Integrations Overview](../README.md#-integrations)
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ **VContainer** is a fast, lightweight dependency injection framework for Unity with minimal overhead. DxMessaging integrates seamlessly with VContainer, allowing you to:
10
+
11
+ - **Inject `IMessageBus`** in any class with deterministic lifetimes
12
+ - **Create per-scope buses** for scene isolation (perfect for additive scenes)
13
+ - **Use DI for construction** + DxMessaging for events (best of both worlds)
14
+ - **Minimal performance overhead** — VContainer + DxMessaging = blazing fast
15
+
16
+ **Why combine DI + Messaging?** Use constructor injection for service dependencies (repositories, managers) and messaging for reactive events (damage taken, item collected). VContainer's scoped lifetimes make it perfect for per-scene message buses.
17
+
18
+ ---
19
+
20
+ ## Quick Start
21
+
22
+ ### Prerequisites
23
+
24
+ - DxMessaging installed via UPM
25
+ - VContainer installed (Git URL or OpenUPM)
26
+
27
+ ### 1. Create a LifetimeScope with DxMessaging
28
+
29
+ ```csharp
30
+ using DxMessaging.Core.MessageBus;
31
+ using UnityEngine;
32
+ using VContainer;
33
+ using VContainer.Unity;
34
+
35
+ public sealed class MessagingLifetimeScope : LifetimeScope
36
+ {
37
+ protected override void Configure(IContainerBuilder builder)
38
+ {
39
+ // Register MessageBus as both concrete and interface
40
+ builder.Register<MessageBus>(Lifetime.Singleton).As<IMessageBus>();
41
+
42
+ // Optional: Enable automatic IMessageRegistrationBuilder binding
43
+ // Requires VCONTAINER_PRESENT define (auto-added by DxMessaging when VContainer detected)
44
+ #if VCONTAINER_PRESENT
45
+ builder.RegisterMessageRegistrationBuilder();
46
+ #endif
47
+ }
48
+ }
49
+ ```
50
+
51
+ #### Add to your scene
52
+
53
+ 1. Create an empty GameObject in your scene
54
+ 1. Add the `MessagingLifetimeScope` component
55
+ 1. This creates a singleton bus for the entire scene
56
+
57
+ **Tip:** Use `Lifetime.Singleton` for project-wide buses, or `Lifetime.Scoped` for isolated scene/feature buses.
58
+
59
+ ---
60
+
61
+ ## Usage Patterns
62
+
63
+ ### Pattern 1: Inject into Plain Classes (Recommended for Services)
64
+
65
+ Use `IMessageRegistrationBuilder` to create message handlers in non-MonoBehaviour classes:
66
+
67
+ ```csharp
68
+ using DxMessaging.Core.MessageBus;
69
+ using DxMessaging.Core.Attributes;
70
+ using VContainer.Unity;
71
+
72
+ // Define a message
73
+ [DxUntargetedMessage]
74
+ [DxAutoConstructor]
75
+ public readonly partial struct PlayerSpawned
76
+ {
77
+ public readonly int playerId;
78
+ }
79
+
80
+ // Service that listens to messages
81
+ public sealed class PlayerService : IStartable, IDisposable
82
+ {
83
+ private readonly MessageRegistrationLease _lease;
84
+
85
+ // Builder is injected automatically when using the scope
86
+ public PlayerService(IMessageRegistrationBuilder registrationBuilder)
87
+ {
88
+ var options = new MessageRegistrationBuildOptions
89
+ {
90
+ Configure = token =>
91
+ {
92
+ _ = token.RegisterUntargeted<PlayerSpawned>(OnPlayerSpawned);
93
+ }
94
+ };
95
+
96
+ _lease = registrationBuilder.Build(options);
97
+ }
98
+
99
+ public void Start()
100
+ {
101
+ _lease.Activate(); // Start listening when container starts
102
+ }
103
+
104
+ public void Dispose()
105
+ {
106
+ _lease.Dispose(); // Clean up when container disposes
107
+ }
108
+
109
+ private static void OnPlayerSpawned(ref PlayerSpawned message)
110
+ {
111
+ UnityEngine.Debug.Log($"Player {message.playerId} spawned!");
112
+ }
113
+ }
114
+ ```
115
+
116
+ #### Register the service in your scope
117
+
118
+ ```csharp
119
+ protected override void Configure(IContainerBuilder builder)
120
+ {
121
+ builder.Register<MessageBus>(Lifetime.Singleton).As<IMessageBus>();
122
+ #if VCONTAINER_PRESENT
123
+ builder.RegisterMessageRegistrationBuilder();
124
+ #endif
125
+
126
+ // Register your service
127
+ builder.RegisterEntryPoint<PlayerService>();
128
+ }
129
+ ```
130
+
131
+ ---
132
+
133
+ ### Pattern 2: Configure MessagingComponents (For Existing MonoBehaviours)
134
+
135
+ ```csharp
136
+ using DxMessaging.Core.MessageBus;
137
+ using DxMessaging.Unity;
138
+ using UnityEngine;
139
+ using VContainer;
140
+ using VContainer.Unity;
141
+
142
+ [RequireComponent(typeof(MessagingComponent))]
143
+ public sealed class MessagingComponentConfigurator : MonoBehaviour, IStartable
144
+ {
145
+ [Inject]
146
+ private readonly IMessageBus _messageBus;
147
+
148
+ private MessagingComponent _messagingComponent;
149
+
150
+ private void Awake()
151
+ {
152
+ _messagingComponent = GetComponent<MessagingComponent>();
153
+ }
154
+
155
+ public void Start()
156
+ {
157
+ _messagingComponent.Configure(_messageBus, MessageBusRebindMode.RebindActive);
158
+ }
159
+ }
160
+ ```
161
+
162
+ #### Usage
163
+
164
+ 1. Add `MessagingComponentConfigurator` alongside any `MessagingComponent` in your prefabs
165
+ 1. VContainer will inject the bus via `IStartable.Start()` before handlers are registered
166
+ 1. Your message handlers now use the container-managed bus
167
+
168
+ ---
169
+
170
+ ### Pattern 3: Inject IMessageBus Directly
171
+
172
+ For simple emission without listening, inject `IMessageBus` directly:
173
+
174
+ ```csharp
175
+ public sealed class GameInitializer : IStartable
176
+ {
177
+ private readonly IMessageBus _messageBus;
178
+
179
+ public GameInitializer(IMessageBus messageBus)
180
+ {
181
+ _messageBus = messageBus;
182
+ }
183
+
184
+ public void Start()
185
+ {
186
+ var message = new GameStarted();
187
+ _messageBus.EmitUntargeted(ref message);
188
+ }
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Advanced: Scene Scopes and Isolation
195
+
196
+ VContainer's scoped lifetimes make it perfect for per-scene message buses. This is useful for additive scenes or isolated gameplay features:
197
+
198
+ ```csharp
199
+ using DxMessaging.Core.MessageBus;
200
+ using VContainer;
201
+ using VContainer.Unity;
202
+
203
+ public sealed class LevelLoader
204
+ {
205
+ private readonly LifetimeScope _parentScope;
206
+
207
+ public LevelLoader(LifetimeScope parentScope)
208
+ {
209
+ _parentScope = parentScope;
210
+ }
211
+
212
+ public LifetimeScope LoadLevel(GameObject lifetimeScopePrefab)
213
+ {
214
+ // Create a child scope with its own MessageBus
215
+ return _parentScope.CreateChildFromPrefab(lifetimeScopePrefab, builder =>
216
+ {
217
+ builder.Register<MessageBus>(Lifetime.Singleton).As<IMessageBus>();
218
+ #if VCONTAINER_PRESENT
219
+ builder.RegisterMessageRegistrationBuilder();
220
+ #endif
221
+ });
222
+ }
223
+ }
224
+ ```
225
+
226
+ ### Benefits
227
+
228
+ - Each scene gets its own isolated message bus
229
+ - Messages don't leak between scenes
230
+ - Perfect for multiplayer lobbies, mini-games, or feature-scoped events
231
+
232
+ ---
233
+
234
+ ## Testing with VContainer
235
+
236
+ ### Unit Tests
237
+
238
+ ```csharp
239
+ using DxMessaging.Core.MessageBus;
240
+ using VContainer;
241
+ using VContainer.Unity;
242
+ using NUnit.Framework;
243
+
244
+ [TestFixture]
245
+ public class GameInitializerTests
246
+ {
247
+ [Test]
248
+ public void Initialize_EmitsGameStarted()
249
+ {
250
+ // Arrange
251
+ var builder = new ContainerBuilder();
252
+ var bus = new MessageBus();
253
+ builder.RegisterInstance<IMessageBus>(bus);
254
+ builder.RegisterEntryPoint<GameInitializer>();
255
+ var container = builder.Build();
256
+
257
+ bool messageReceived = false;
258
+ var handler = new MessageHandler(new InstanceId(1), bus) { active = true };
259
+ var token = MessageRegistrationToken.Create(handler, bus);
260
+ _ = token.RegisterUntargeted<GameStarted>(ref msg => messageReceived = true);
261
+ token.Enable();
262
+
263
+ // Act
264
+ container.Resolve<GameInitializer>().Start();
265
+
266
+ // Assert
267
+ Assert.IsTrue(messageReceived);
268
+ }
269
+ }
270
+ ```
271
+
272
+ ### Play-Mode Tests
273
+
274
+ For play-mode tests, create a temporary `LifetimeScope`:
275
+
276
+ ```csharp
277
+ [UnityTest]
278
+ public IEnumerator PlayMode_MessageBusIsolation()
279
+ {
280
+ // Create isolated scope for this test
281
+ var scope = LifetimeScope.Create(builder =>
282
+ {
283
+ builder.Register<MessageBus>(Lifetime.Singleton).As<IMessageBus>();
284
+ });
285
+
286
+ var bus = scope.Container.Resolve<IMessageBus>();
287
+ // ... test logic ...
288
+
289
+ scope.Dispose(); // Clean up
290
+ yield return null;
291
+ }
292
+ ```
293
+
294
+ ---
295
+
296
+ ## Checklist
297
+
298
+ ### Initial Setup
299
+
300
+ - [ ] Install DxMessaging and VContainer
301
+ - [ ] Create `MessagingLifetimeScope` with `builder.Register<MessageBus>().As<IMessageBus>()`
302
+ - [ ] Add scope to your scene as a GameObject component
303
+ - [ ] Add `#if VCONTAINER_PRESENT` check and call `builder.RegisterMessageRegistrationBuilder()`
304
+
305
+ ### Integration
306
+
307
+ - [ ] Use `IMessageRegistrationBuilder` in plain classes with `IStartable`/`IDisposable`
308
+ - [ ] Add `MessagingComponentConfigurator` to prefabs with `MessagingComponent`
309
+ - [ ] Replace `MessageHandler.MessageBus` references with injected `IMessageBus`
310
+ - [ ] Consider using scoped buses for scene isolation
311
+
312
+ ### Testing
313
+
314
+ - [ ] Create isolated `ContainerBuilder` instances in tests
315
+ - [ ] Use `builder.RegisterInstance<IMessageBus>(new MessageBus())` for test buses
316
+ - [ ] Dispose scopes after tests to ensure clean teardown
317
+
318
+ ---
319
+
320
+ ## Next Steps
321
+
322
+ - **[Zenject Integration](Zenject.md)** — Full-featured DI with extensive Unity support
323
+ - **[Reflex Integration](Reflex.md)** — Minimal DI framework
324
+ - **[Back to Documentation Hub](../Index.md)** — Browse all docs
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: 14b0f2e146fecb24eb5317b196d6af62
3
+ TextScriptImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant:
@@ -0,0 +1,333 @@
1
+ # DxMessaging + Zenject
2
+
3
+ [← Back to Integrations Overview](../README.md#-integrations)
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ **Zenject** (also known as Extenject) is a powerful dependency injection framework for Unity. DxMessaging integrates seamlessly with Zenject, allowing you to:
10
+
11
+ - **Inject `IMessageBus`** as a singleton dependency in any class
12
+ - **Use DI for construction** + DxMessaging for events (best of both worlds)
13
+ - **Create per-scope message buses** for scene or gameplay isolation
14
+ - **Bridge to SignalBus** for gradual migration from Zenject Signals
15
+
16
+ **Why combine DI + Messaging?** Use constructor injection for service dependencies (repositories, managers) and messaging for reactive events (damage taken, item collected). This keeps your architecture clean and testable.
17
+
18
+ ---
19
+
20
+ ## Quick Start
21
+
22
+ ### Prerequisites
23
+
24
+ - DxMessaging installed via UPM
25
+ - Zenject/Extenject installed (source or UPM)
26
+
27
+ ### 1. Create an Installer
28
+
29
+ Create a `DxMessagingInstaller` to bind the message bus to your Zenject container:
30
+
31
+ ```csharp
32
+ using DxMessaging.Core.MessageBus;
33
+ using Zenject;
34
+
35
+ public sealed class DxMessagingInstaller : MonoInstaller
36
+ {
37
+ public override void InstallBindings()
38
+ {
39
+ // Bind MessageBus as a singleton and expose IMessageBus interface
40
+ Container.BindInterfacesAndSelfTo<MessageBus>().AsSingle();
41
+
42
+ // Optional: Enable automatic IMessageRegistrationBuilder binding
43
+ // Requires ZENJECT_PRESENT define (auto-added by DxMessaging when Zenject detected)
44
+ #if ZENJECT_PRESENT
45
+ Container.RegisterMessageRegistrationBuilder();
46
+ #endif
47
+ }
48
+ }
49
+ ```
50
+
51
+ #### Add to your ProjectContext
52
+
53
+ 1. Select (or create) your `ProjectContext` prefab
54
+ 1. Add `DxMessagingInstaller` as a MonoInstaller
55
+ 1. Save the prefab
56
+
57
+ ---
58
+
59
+ ## Usage Patterns
60
+
61
+ ### Pattern 1: Inject into Plain Classes (Recommended for Services)
62
+
63
+ Use `IMessageRegistrationBuilder` to create message handlers in non-MonoBehaviour classes:
64
+
65
+ ```csharp
66
+ using DxMessaging.Core.MessageBus;
67
+ using DxMessaging.Core.Attributes;
68
+ using Zenject;
69
+
70
+ // Define a message
71
+ [DxUntargetedMessage]
72
+ [DxAutoConstructor]
73
+ public readonly partial struct PlayerSpawned
74
+ {
75
+ public readonly int playerId;
76
+ }
77
+
78
+ // Service that listens to messages
79
+ public sealed class PlayerController : IInitializable, IDisposable
80
+ {
81
+ private readonly MessageRegistrationLease _lease;
82
+
83
+ // Builder is injected automatically when using the installer
84
+ public PlayerController(IMessageRegistrationBuilder registrationBuilder)
85
+ {
86
+ var options = new MessageRegistrationBuildOptions
87
+ {
88
+ Configure = token =>
89
+ {
90
+ _ = token.RegisterUntargeted<PlayerSpawned>(OnPlayerSpawned);
91
+ }
92
+ };
93
+
94
+ _lease = registrationBuilder.Build(options);
95
+ }
96
+
97
+ public void Initialize()
98
+ {
99
+ _lease.Activate(); // Start listening when container initializes
100
+ }
101
+
102
+ public void Dispose()
103
+ {
104
+ _lease.Dispose(); // Clean up when container disposes
105
+ }
106
+
107
+ private static void OnPlayerSpawned(ref PlayerSpawned message)
108
+ {
109
+ UnityEngine.Debug.Log($"Player {message.playerId} spawned!");
110
+ }
111
+ }
112
+ ```
113
+
114
+ #### Register the service in your installer
115
+
116
+ ```csharp
117
+ public sealed class GameInstaller : MonoInstaller
118
+ {
119
+ public override void InstallBindings()
120
+ {
121
+ Container.BindInterfacesAndSelfTo<PlayerController>().AsSingle();
122
+ }
123
+ }
124
+ ```
125
+
126
+ ---
127
+
128
+ ### Pattern 2: Configure MessagingComponents (For Existing MonoBehaviours)
129
+
130
+ If you have existing `MessageAwareComponent` scripts, you can inject the container-managed bus into them:
131
+
132
+ ```csharp
133
+ using DxMessaging.Core.MessageBus;
134
+ using DxMessaging.Unity;
135
+ using UnityEngine;
136
+ using Zenject;
137
+
138
+ [RequireComponent(typeof(MessagingComponent))]
139
+ public sealed class MessagingComponentConfigurator : MonoBehaviour
140
+ {
141
+ [Inject]
142
+ private IMessageBus _messageBus;
143
+
144
+ private void Awake()
145
+ {
146
+ MessagingComponent component = GetComponent<MessagingComponent>();
147
+ component.Configure(_messageBus, MessageBusRebindMode.RebindActive);
148
+ }
149
+ }
150
+ ```
151
+
152
+ #### Usage
153
+
154
+ 1. Add `MessagingComponentConfigurator` alongside any `MessagingComponent` in your prefabs
155
+ 1. Zenject will inject the bus before `RegisterMessageHandlers` is called
156
+ 1. Your message handlers now use the container-managed bus
157
+
158
+ **Alternative approach:** Extend `MessageAwareComponent` and override `Awake`:
159
+
160
+ ```csharp
161
+ public class ZenjectAwareComponent : MessageAwareComponent
162
+ {
163
+ [Inject]
164
+ private IMessageBus _messageBus;
165
+
166
+ protected override void Awake()
167
+ {
168
+ Configure(_messageBus, MessageBusRebindMode.RebindActive);
169
+ base.Awake();
170
+ }
171
+ }
172
+ ```
173
+
174
+ ---
175
+
176
+ ### Pattern 3: Inject IMessageBus Directly
177
+
178
+ For simple cases, inject `IMessageBus` and emit messages directly:
179
+
180
+ ```csharp
181
+ public sealed class GameInitializer : IInitializable
182
+ {
183
+ private readonly IMessageBus _messageBus;
184
+
185
+ public GameInitializer(IMessageBus messageBus)
186
+ {
187
+ _messageBus = messageBus;
188
+ }
189
+
190
+ public void Initialize()
191
+ {
192
+ var message = new GameStarted();
193
+ _messageBus.EmitUntargeted(ref message);
194
+ }
195
+ }
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Advanced: Bridging to Zenject Signals
201
+
202
+ If you're gradually migrating from Zenject Signals to DxMessaging, you can create a bridge:
203
+
204
+ ```csharp
205
+ using DxMessaging.Core;
206
+ using DxMessaging.Core.MessageBus;
207
+ using System;
208
+ using Zenject;
209
+
210
+ [DxUntargetedMessage]
211
+ [DxAutoConstructor]
212
+ public readonly partial struct SceneTransition
213
+ {
214
+ public readonly string sceneName;
215
+ }
216
+
217
+ public sealed class DxToSignalBridge : IInitializable, IDisposable
218
+ {
219
+ private readonly IMessageBus _messageBus;
220
+ private readonly SignalBus _signalBus;
221
+ private MessageRegistrationToken _token;
222
+
223
+ public DxToSignalBridge(IMessageBus messageBus, SignalBus signalBus)
224
+ {
225
+ _messageBus = messageBus;
226
+ _signalBus = signalBus;
227
+ }
228
+
229
+ public void Initialize()
230
+ {
231
+ // Create a handler to listen to DxMessaging events
232
+ var handler = new MessageHandler(new InstanceId(0), _messageBus)
233
+ {
234
+ active = true
235
+ };
236
+ _token = MessageRegistrationToken.Create(handler, _messageBus);
237
+
238
+ // Bridge DxMessaging → Zenject Signals
239
+ _ = _token.RegisterUntargeted<SceneTransition>(OnSceneTransition);
240
+ _token.Enable();
241
+ }
242
+
243
+ public void Dispose()
244
+ {
245
+ _token?.Disable();
246
+ }
247
+
248
+ private void OnSceneTransition(ref SceneTransition message)
249
+ {
250
+ // Forward to SignalBus for legacy consumers
251
+ _signalBus.Fire(message);
252
+ }
253
+ }
254
+ ```
255
+
256
+ ### Register the bridge in your installer
257
+
258
+ ```csharp
259
+ public override void InstallBindings()
260
+ {
261
+ Container.BindInterfacesAndSelfTo<DxToSignalBridge>().AsSingle();
262
+ Container.DeclareSignal<SceneTransition>();
263
+ }
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Testing with Zenject
269
+
270
+ ### Unit Tests
271
+
272
+ ```csharp
273
+ using DxMessaging.Core.MessageBus;
274
+ using Zenject;
275
+ using NUnit.Framework;
276
+
277
+ [TestFixture]
278
+ public class GameInitializerTests : ZenjectUnitTestFixture
279
+ {
280
+ [Test]
281
+ public void Initialize_EmitsGameStarted()
282
+ {
283
+ // Arrange
284
+ var bus = new MessageBus();
285
+ Container.Bind<IMessageBus>().FromInstance(bus).AsSingle();
286
+ Container.BindInterfacesAndSelfTo<GameInitializer>().AsSingle();
287
+
288
+ bool messageReceived = false;
289
+ var handler = new MessageHandler(new InstanceId(1), bus) { active = true };
290
+ var token = MessageRegistrationToken.Create(handler, bus);
291
+ _ = token.RegisterUntargeted<GameStarted>(ref msg => messageReceived = true);
292
+ token.Enable();
293
+
294
+ // Act
295
+ var initializer = Container.Resolve<GameInitializer>();
296
+ initializer.Initialize();
297
+
298
+ // Assert
299
+ Assert.IsTrue(messageReceived);
300
+ }
301
+ }
302
+ ```
303
+
304
+ ---
305
+
306
+ ## Checklist
307
+
308
+ ### Initial Setup
309
+
310
+ - [ ] Install DxMessaging and Zenject/Extenject
311
+ - [ ] Create `DxMessagingInstaller` with `Container.BindInterfacesAndSelfTo<MessageBus>()`
312
+ - [ ] Add installer to your `ProjectContext`
313
+ - [ ] Add `#if ZENJECT_PRESENT` check and call `Container.RegisterMessageRegistrationBuilder()`
314
+
315
+ ### Integration
316
+
317
+ - [ ] Use `IMessageRegistrationBuilder` in plain classes with `IInitializable`/`IDisposable`
318
+ - [ ] Add `MessagingComponentConfigurator` to prefabs with `MessagingComponent`
319
+ - [ ] Replace `MessageHandler.MessageBus` references with injected `IMessageBus`
320
+ - [ ] Consider bridging to SignalBus if migrating from Zenject Signals
321
+
322
+ ### Testing
323
+
324
+ - [ ] Inject `IMessageBus` in tests using `FromInstance(new MessageBus())`
325
+ - [ ] Verify messages flow through the container-provided bus
326
+
327
+ ---
328
+
329
+ ## Next Steps
330
+
331
+ - **[VContainer Integration](VContainer.md)** — Lightweight alternative to Zenject
332
+ - **[Reflex Integration](Reflex.md)** — Minimal DI framework
333
+ - **[Back to Documentation Hub](../Index.md)** — Browse all docs
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: d76f08987c5a6cf4db56ae8a9ab69e33
3
+ TextScriptImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant:
@@ -1,5 +1,6 @@
1
1
  fileFormatVersion: 2
2
- guid: f3c8044ad004aee409e169cdae65a86d
2
+ guid: b7f8fcdfff069bc4ead3d4df106dd46b
3
+ folderAsset: yes
3
4
  DefaultImporter:
4
5
  externalObjects: {}
5
6
  userData: