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
@@ -348,7 +348,143 @@ namespace DxMessaging.Core
348
348
  /// <summary>
349
349
  /// Global message bus used when no explicit bus is provided.
350
350
  /// </summary>
351
- public static readonly MessageBus.MessageBus MessageBus = new();
351
+ private static IMessageBus _globalMessageBus;
352
+
353
+ private static readonly MessageBus.MessageBus _defaultGlobalMessageBus = new();
354
+
355
+ /// <summary>
356
+ /// Gets the process-wide <see cref="IMessageBus"/> used when no explicit bus is supplied.
357
+ /// </summary>
358
+ /// <remarks>
359
+ /// This mirrors the legacy singleton so existing code continues to function. Use
360
+ /// <see cref="SetGlobalMessageBus(MessageBus.MessageBus)"/> to replace the instance (for example from a DI container) and
361
+ /// <see cref="ResetGlobalMessageBus"/> to restore the stock configuration afterwards.
362
+ /// </remarks>
363
+ public static IMessageBus MessageBus => _globalMessageBus;
364
+
365
+ /// <summary>
366
+ /// Gets the original global <see cref="IMessageBus"/> instance created during static initialisation.
367
+ /// </summary>
368
+ /// <remarks>
369
+ /// This reference never changes even when <see cref="SetGlobalMessageBus(IMessageBus)"/> is invoked.
370
+ /// </remarks>
371
+ public static IMessageBus InitialGlobalMessageBus => _defaultGlobalMessageBus;
372
+
373
+ static MessageHandler()
374
+ {
375
+ _globalMessageBus = _defaultGlobalMessageBus;
376
+ }
377
+
378
+ /// <summary>
379
+ /// Replaces the global <see cref="MessageBus.MessageBus"/> instance returned by <see cref="MessageBus"/>.
380
+ /// </summary>
381
+ /// <param name="messageBus">Instance to expose globally.</param>
382
+ /// <exception cref="ArgumentNullException">
383
+ /// Thrown when <paramref name="messageBus"/> is <see langword="null"/>.
384
+ /// </exception>
385
+ /// <remarks>
386
+ /// This is primarily intended for integration tests or dependency injection bootstrap code. Invoke
387
+ /// <see cref="ResetGlobalMessageBus"/> when the customisation is no longer required.
388
+ /// </remarks>
389
+ public static void SetGlobalMessageBus(MessageBus.MessageBus messageBus)
390
+ {
391
+ if (messageBus == null)
392
+ {
393
+ throw new ArgumentNullException(nameof(messageBus));
394
+ }
395
+
396
+ _globalMessageBus = messageBus;
397
+ }
398
+
399
+ /// <summary>
400
+ /// Replaces the global message bus with an arbitrary <see cref="IMessageBus"/> implementation.
401
+ /// </summary>
402
+ /// <param name="messageBus">Instance to expose globally.</param>
403
+ /// <exception cref="ArgumentNullException">
404
+ /// Thrown when <paramref name="messageBus"/> is <see langword="null"/>.
405
+ /// </exception>
406
+ public static void SetGlobalMessageBus(IMessageBus messageBus)
407
+ {
408
+ if (messageBus == null)
409
+ {
410
+ throw new ArgumentNullException(nameof(messageBus));
411
+ }
412
+
413
+ _globalMessageBus = messageBus;
414
+ }
415
+
416
+ /// <summary>
417
+ /// Restores the global <see cref="MessageBus.MessageBus"/> to the built-in default instance.
418
+ /// </summary>
419
+ /// <remarks>
420
+ /// The default instance is created during static initialisation and reused across resets to minimise allocations.
421
+ /// </remarks>
422
+ public static void ResetGlobalMessageBus()
423
+ {
424
+ _globalMessageBus = _defaultGlobalMessageBus;
425
+ }
426
+
427
+ /// <summary>
428
+ /// Temporarily overrides the global message bus until the returned scope is disposed.
429
+ /// </summary>
430
+ /// <param name="messageBus">Message bus to expose for the duration of the scope.</param>
431
+ /// <returns>An <see cref="IDisposable"/> scope that restores the previous bus on dispose.</returns>
432
+ public static GlobalMessageBusScope OverrideGlobalMessageBus(IMessageBus messageBus)
433
+ {
434
+ return new GlobalMessageBusScope(messageBus);
435
+ }
436
+
437
+ /// <summary>
438
+ /// Represents a disposable override scope for the global message bus.
439
+ /// </summary>
440
+ public struct GlobalMessageBusScope : IDisposable
441
+ {
442
+ private readonly IMessageBus _previous;
443
+ private bool _disposed;
444
+
445
+ internal GlobalMessageBusScope(IMessageBus messageBus)
446
+ {
447
+ if (messageBus == null)
448
+ {
449
+ throw new ArgumentNullException(nameof(messageBus));
450
+ }
451
+
452
+ _previous = MessageBus;
453
+ _disposed = false;
454
+
455
+ if (messageBus is MessageBus.MessageBus concrete)
456
+ {
457
+ SetGlobalMessageBus(concrete);
458
+ }
459
+ else
460
+ {
461
+ SetGlobalMessageBus(messageBus);
462
+ }
463
+ }
464
+
465
+ public void Dispose()
466
+ {
467
+ if (_disposed)
468
+ {
469
+ return;
470
+ }
471
+
472
+ if (_previous is MessageBus.MessageBus concrete)
473
+ {
474
+ SetGlobalMessageBus(concrete);
475
+ }
476
+ else if (_previous != null)
477
+ {
478
+ SetGlobalMessageBus(_previous);
479
+ }
480
+ else
481
+ {
482
+ ResetGlobalMessageBus();
483
+ }
484
+
485
+ _disposed = true;
486
+ }
487
+ }
352
488
 
353
489
  /// <summary>
354
490
  /// Whether this MessageHandler will process messages.
@@ -367,11 +503,43 @@ namespace DxMessaging.Core
367
503
  /// Ideally, this would be something like a Dictionary[T, Handler[T]], but that can't be done with C#s type system.
368
504
  /// </note>
369
505
  private readonly List<MessageCache<object>> _handlersByTypeByMessageBus;
506
+ private IMessageBus _defaultMessageBus;
370
507
 
371
- public MessageHandler(InstanceId owner)
508
+ /// <summary>
509
+ /// Gets the <see cref="IMessageBus"/> that will be used when a registration does not specify one explicitly.
510
+ /// </summary>
511
+ /// <remarks>
512
+ /// When no override has been provided via <see cref="SetDefaultMessageBus"/>, this value defers to the global
513
+ /// <see cref="MessageBus"/> singleton.
514
+ /// </remarks>
515
+ public IMessageBus DefaultMessageBus => _defaultMessageBus ?? MessageBus;
516
+
517
+ public MessageHandler(InstanceId owner, IMessageBus defaultMessageBus = null)
372
518
  {
373
519
  this.owner = owner;
374
520
  _handlersByTypeByMessageBus = new List<MessageCache<object>>();
521
+ _defaultMessageBus = defaultMessageBus;
522
+ }
523
+
524
+ /// <summary>
525
+ /// Assigns an <see cref="IMessageBus"/> for registrations that omit an explicit bus parameter.
526
+ /// </summary>
527
+ /// <param name="messageBus">
528
+ /// Bus to use; pass <see langword="null"/> to revert to the global <see cref="MessageBus"/> singleton.
529
+ /// </param>
530
+ /// <remarks>
531
+ /// This allows a handler to participate in dependency injection scenarios without forcing every caller to supply
532
+ /// a bus manually.
533
+ /// </remarks>
534
+ public void SetDefaultMessageBus(IMessageBus messageBus)
535
+ {
536
+ _defaultMessageBus = messageBus;
537
+ }
538
+
539
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
540
+ private IMessageBus ResolveMessageBus(IMessageBus messageBus)
541
+ {
542
+ return messageBus ?? _defaultMessageBus ?? MessageBus;
375
543
  }
376
544
 
377
545
  /// <summary>
@@ -864,7 +1032,7 @@ namespace DxMessaging.Core
864
1032
  IMessageBus messageBus = null
865
1033
  )
866
1034
  {
867
- messageBus ??= MessageBus;
1035
+ messageBus = ResolveMessageBus(messageBus);
868
1036
  Action messageBusDeregistration = messageBus.RegisterGlobalAcceptAll(this);
869
1037
  TypedHandler<IMessage> typedHandler = GetOrCreateHandlerForType<IMessage>(messageBus);
870
1038
 
@@ -916,7 +1084,7 @@ namespace DxMessaging.Core
916
1084
  IMessageBus messageBus = null
917
1085
  )
918
1086
  {
919
- messageBus ??= MessageBus;
1087
+ messageBus = ResolveMessageBus(messageBus);
920
1088
  Action messageBusDeregistration = messageBus.RegisterGlobalAcceptAll(this);
921
1089
  TypedHandler<IMessage> typedHandler = GetOrCreateHandlerForType<IMessage>(messageBus);
922
1090
 
@@ -968,7 +1136,7 @@ namespace DxMessaging.Core
968
1136
  )
969
1137
  where T : ITargetedMessage
970
1138
  {
971
- messageBus ??= MessageBus;
1139
+ messageBus = ResolveMessageBus(messageBus);
972
1140
  Action messageBusDeregistration = messageBus.RegisterTargeted<T>(
973
1141
  target,
974
1142
  this,
@@ -1003,7 +1171,7 @@ namespace DxMessaging.Core
1003
1171
  )
1004
1172
  where T : ITargetedMessage
1005
1173
  {
1006
- messageBus ??= MessageBus;
1174
+ messageBus = ResolveMessageBus(messageBus);
1007
1175
  Action messageBusDeregistration = messageBus.RegisterTargeted<T>(
1008
1176
  target,
1009
1177
  this,
@@ -1038,7 +1206,7 @@ namespace DxMessaging.Core
1038
1206
  )
1039
1207
  where T : ITargetedMessage
1040
1208
  {
1041
- messageBus ??= MessageBus;
1209
+ messageBus = ResolveMessageBus(messageBus);
1042
1210
  Action messageBusDeregistration = messageBus.RegisterTargetedPostProcessor<T>(
1043
1211
  target,
1044
1212
  this,
@@ -1073,7 +1241,7 @@ namespace DxMessaging.Core
1073
1241
  )
1074
1242
  where T : ITargetedMessage
1075
1243
  {
1076
- messageBus ??= MessageBus;
1244
+ messageBus = ResolveMessageBus(messageBus);
1077
1245
  Action messageBusDeregistration = messageBus.RegisterTargetedPostProcessor<T>(
1078
1246
  target,
1079
1247
  this,
@@ -1106,7 +1274,7 @@ namespace DxMessaging.Core
1106
1274
  )
1107
1275
  where T : ITargetedMessage
1108
1276
  {
1109
- messageBus ??= MessageBus;
1277
+ messageBus = ResolveMessageBus(messageBus);
1110
1278
  Action messageBusDeregistration =
1111
1279
  messageBus.RegisterTargetedWithoutTargetingPostProcessor<T>(
1112
1280
  priority: priority,
@@ -1138,7 +1306,7 @@ namespace DxMessaging.Core
1138
1306
  )
1139
1307
  where T : ITargetedMessage
1140
1308
  {
1141
- messageBus ??= MessageBus;
1309
+ messageBus = ResolveMessageBus(messageBus);
1142
1310
  Action messageBusDeregistration =
1143
1311
  messageBus.RegisterTargetedWithoutTargetingPostProcessor<T>(
1144
1312
  priority: priority,
@@ -1170,7 +1338,7 @@ namespace DxMessaging.Core
1170
1338
  )
1171
1339
  where T : ITargetedMessage
1172
1340
  {
1173
- messageBus ??= MessageBus;
1341
+ messageBus = ResolveMessageBus(messageBus);
1174
1342
  Action messageBusDeregistration = messageBus.RegisterTargetedWithoutTargeting<T>(
1175
1343
  this,
1176
1344
  priority: priority
@@ -1201,7 +1369,7 @@ namespace DxMessaging.Core
1201
1369
  )
1202
1370
  where T : ITargetedMessage
1203
1371
  {
1204
- messageBus ??= MessageBus;
1372
+ messageBus = ResolveMessageBus(messageBus);
1205
1373
  Action messageBusDeregistration = messageBus.RegisterTargetedWithoutTargeting<T>(
1206
1374
  this,
1207
1375
  priority: priority
@@ -1232,7 +1400,7 @@ namespace DxMessaging.Core
1232
1400
  )
1233
1401
  where T : IUntargetedMessage
1234
1402
  {
1235
- messageBus ??= MessageBus;
1403
+ messageBus = ResolveMessageBus(messageBus);
1236
1404
  Action messageBusDeregistration = messageBus.RegisterUntargeted<T>(
1237
1405
  this,
1238
1406
  priority: priority
@@ -1263,7 +1431,7 @@ namespace DxMessaging.Core
1263
1431
  )
1264
1432
  where T : IUntargetedMessage
1265
1433
  {
1266
- messageBus ??= MessageBus;
1434
+ messageBus = ResolveMessageBus(messageBus);
1267
1435
  Action messageBusDeregistration = messageBus.RegisterUntargeted<T>(
1268
1436
  this,
1269
1437
  priority: priority
@@ -1294,7 +1462,7 @@ namespace DxMessaging.Core
1294
1462
  )
1295
1463
  where T : IUntargetedMessage
1296
1464
  {
1297
- messageBus ??= MessageBus;
1465
+ messageBus = ResolveMessageBus(messageBus);
1298
1466
  Action messageBusDeregistration = messageBus.RegisterUntargetedPostProcessor<T>(
1299
1467
  priority: priority,
1300
1468
  messageHandler: this
@@ -1325,7 +1493,7 @@ namespace DxMessaging.Core
1325
1493
  )
1326
1494
  where T : IUntargetedMessage
1327
1495
  {
1328
- messageBus ??= MessageBus;
1496
+ messageBus = ResolveMessageBus(messageBus);
1329
1497
  Action messageBusDeregistration = messageBus.RegisterUntargetedPostProcessor<T>(
1330
1498
  priority: priority,
1331
1499
  messageHandler: this
@@ -1358,7 +1526,7 @@ namespace DxMessaging.Core
1358
1526
  )
1359
1527
  where T : IBroadcastMessage
1360
1528
  {
1361
- messageBus ??= MessageBus;
1529
+ messageBus = ResolveMessageBus(messageBus);
1362
1530
  Action messageBusDeregistration = messageBus.RegisterSourcedBroadcast<T>(
1363
1531
  source,
1364
1532
  this,
@@ -1394,7 +1562,7 @@ namespace DxMessaging.Core
1394
1562
  )
1395
1563
  where T : IBroadcastMessage
1396
1564
  {
1397
- messageBus ??= MessageBus;
1565
+ messageBus = ResolveMessageBus(messageBus);
1398
1566
  Action messageBusDeregistration = messageBus.RegisterSourcedBroadcast<T>(
1399
1567
  source,
1400
1568
  this,
@@ -1427,7 +1595,7 @@ namespace DxMessaging.Core
1427
1595
  )
1428
1596
  where T : IBroadcastMessage
1429
1597
  {
1430
- messageBus ??= MessageBus;
1598
+ messageBus = ResolveMessageBus(messageBus);
1431
1599
  Action messageBusDeregistration = messageBus.RegisterSourcedBroadcastWithoutSource<T>(
1432
1600
  this,
1433
1601
  priority: priority
@@ -1458,7 +1626,7 @@ namespace DxMessaging.Core
1458
1626
  )
1459
1627
  where T : IBroadcastMessage
1460
1628
  {
1461
- messageBus ??= MessageBus;
1629
+ messageBus = ResolveMessageBus(messageBus);
1462
1630
  Action messageBusDeregistration = messageBus.RegisterSourcedBroadcastWithoutSource<T>(
1463
1631
  this,
1464
1632
  priority: priority
@@ -1491,7 +1659,7 @@ namespace DxMessaging.Core
1491
1659
  )
1492
1660
  where T : IBroadcastMessage
1493
1661
  {
1494
- messageBus ??= MessageBus;
1662
+ messageBus = ResolveMessageBus(messageBus);
1495
1663
  Action messageBusDeregistration = messageBus.RegisterBroadcastPostProcessor<T>(
1496
1664
  source,
1497
1665
  messageHandler: this,
@@ -1526,7 +1694,7 @@ namespace DxMessaging.Core
1526
1694
  )
1527
1695
  where T : IBroadcastMessage
1528
1696
  {
1529
- messageBus ??= MessageBus;
1697
+ messageBus = ResolveMessageBus(messageBus);
1530
1698
  Action messageBusDeregistration = messageBus.RegisterBroadcastPostProcessor<T>(
1531
1699
  source,
1532
1700
  priority: priority,
@@ -1559,7 +1727,7 @@ namespace DxMessaging.Core
1559
1727
  )
1560
1728
  where T : IBroadcastMessage
1561
1729
  {
1562
- messageBus ??= MessageBus;
1730
+ messageBus = ResolveMessageBus(messageBus);
1563
1731
  Action messageBusDeregistration =
1564
1732
  messageBus.RegisterBroadcastWithoutSourcePostProcessor<T>(
1565
1733
  priority: priority,
@@ -1591,7 +1759,7 @@ namespace DxMessaging.Core
1591
1759
  )
1592
1760
  where T : IBroadcastMessage
1593
1761
  {
1594
- messageBus ??= MessageBus;
1762
+ messageBus = ResolveMessageBus(messageBus);
1595
1763
  Action messageBusDeregistration =
1596
1764
  messageBus.RegisterBroadcastWithoutSourcePostProcessor<T>(
1597
1765
  priority: priority,
@@ -1622,7 +1790,8 @@ namespace DxMessaging.Core
1622
1790
  )
1623
1791
  where T : IUntargetedMessage
1624
1792
  {
1625
- return (messageBus ?? MessageBus).RegisterUntargetedInterceptor(interceptor, priority);
1793
+ messageBus = ResolveMessageBus(messageBus);
1794
+ return messageBus.RegisterUntargetedInterceptor(interceptor, priority);
1626
1795
  }
1627
1796
 
1628
1797
  /// <summary>
@@ -1640,7 +1809,8 @@ namespace DxMessaging.Core
1640
1809
  )
1641
1810
  where T : IBroadcastMessage
1642
1811
  {
1643
- return (messageBus ?? MessageBus).RegisterBroadcastInterceptor(interceptor, priority);
1812
+ messageBus = ResolveMessageBus(messageBus);
1813
+ return messageBus.RegisterBroadcastInterceptor(interceptor, priority);
1644
1814
  }
1645
1815
 
1646
1816
  /// <summary>
@@ -1658,7 +1828,8 @@ namespace DxMessaging.Core
1658
1828
  )
1659
1829
  where T : ITargetedMessage
1660
1830
  {
1661
- return (messageBus ?? MessageBus).RegisterTargetedInterceptor(interceptor, priority);
1831
+ messageBus = ResolveMessageBus(messageBus);
1832
+ return messageBus.RegisterTargetedInterceptor(interceptor, priority);
1662
1833
  }
1663
1834
 
1664
1835
  public override bool Equals(object obj)
@@ -59,7 +59,7 @@ namespace DxMessaging.Core
59
59
 
60
60
  private readonly Dictionary<MessageRegistrationHandle, Action> _registrations = new();
61
61
  private readonly Dictionary<MessageRegistrationHandle, Action> _deregistrations = new();
62
- private readonly List<Action> _deregistrationQueue = new();
62
+ private readonly List<Action> _actionQueue = new();
63
63
  internal readonly Dictionary<
64
64
  MessageRegistrationHandle,
65
65
  MessageRegistrationMetadata
@@ -69,7 +69,7 @@ namespace DxMessaging.Core
69
69
  IMessageBus.GlobalMessageBufferSize
70
70
  );
71
71
 
72
- private readonly IMessageBus _messageBus;
72
+ private IMessageBus _messageBus;
73
73
  private bool _enabled;
74
74
  private bool _diagnosticMode = IMessageBus.GlobalDiagnosticsMode;
75
75
 
@@ -359,7 +359,7 @@ namespace DxMessaging.Core
359
359
  )
360
360
  );
361
361
  }
362
- #else
362
+ #endif
363
363
 
364
364
  /// <summary>
365
365
  /// Stages a registration of the provided MessageHandler to accept TargetedMessages of the given type targeted towards the provided target.
@@ -475,9 +475,9 @@ namespace DxMessaging.Core
475
475
  _messageBus
476
476
  );
477
477
 
478
- void AugmentedHandler(ref T message)
478
+ void AugmentedHandler(T message)
479
479
  {
480
- targetedPostProcessor(ref message);
480
+ targetedPostProcessor(message);
481
481
  if (_diagnosticMode)
482
482
  {
483
483
  _callCounts[handle] = _callCounts.GetValueOrDefault(handle) + 1;
@@ -493,9 +493,7 @@ namespace DxMessaging.Core
493
493
  priority
494
494
  )
495
495
  );
496
- ;
497
496
  }
498
- #endif
499
497
 
500
498
  /// <summary>
501
499
  /// Stages a registration of the provided MessageHandler to accept TargetedMessages of the given type targeted towards anything (including itself).
@@ -1246,7 +1244,7 @@ namespace DxMessaging.Core
1246
1244
  )
1247
1245
  );
1248
1246
  }
1249
- #else
1247
+ #endif
1250
1248
 
1251
1249
  /// <summary>
1252
1250
  /// Stages a registration of the provided MessageHandler to accept BroadcastMessages of the given type.
@@ -1331,7 +1329,6 @@ namespace DxMessaging.Core
1331
1329
  {
1332
1330
  return RegisterBroadcastPostProcessorInternal(source, broadcastPostProcessor, priority);
1333
1331
  }
1334
- #endif
1335
1332
 
1336
1333
  /// <summary>
1337
1334
  /// Stages a registration of the provided MessageHandler to accept BroadcastMessages of the given type.
@@ -1846,13 +1843,11 @@ namespace DxMessaging.Core
1846
1843
 
1847
1844
  if (_registrations is { Count: > 0 })
1848
1845
  {
1849
- Dictionary<
1850
- MessageRegistrationHandle,
1851
- Action
1852
- >.ValueCollection.Enumerator enumerator = _registrations.Values.GetEnumerator();
1853
- while (enumerator.MoveNext())
1846
+ _actionQueue.Clear();
1847
+ _actionQueue.AddRange(_registrations.Values);
1848
+ foreach (Action action in _actionQueue)
1854
1849
  {
1855
- enumerator.Current();
1850
+ action();
1856
1851
  }
1857
1852
  }
1858
1853
 
@@ -1879,9 +1874,9 @@ namespace DxMessaging.Core
1879
1874
 
1880
1875
  if (_deregistrations is { Count: > 0 })
1881
1876
  {
1882
- _deregistrationQueue.Clear();
1883
- _deregistrationQueue.AddRange(_deregistrations.Values);
1884
- foreach (Action deregistration in _deregistrationQueue)
1877
+ _actionQueue.Clear();
1878
+ _actionQueue.AddRange(_deregistrations.Values);
1879
+ foreach (Action deregistration in _actionQueue)
1885
1880
  {
1886
1881
  deregistration?.Invoke();
1887
1882
  }
@@ -1906,9 +1901,9 @@ namespace DxMessaging.Core
1906
1901
  {
1907
1902
  if (_deregistrations is { Count: > 0 })
1908
1903
  {
1909
- _deregistrationQueue.Clear();
1910
- _deregistrationQueue.AddRange(_deregistrations.Values);
1911
- foreach (Action deregistration in _deregistrationQueue)
1904
+ _actionQueue.Clear();
1905
+ _actionQueue.AddRange(_deregistrations.Values);
1906
+ foreach (Action deregistration in _actionQueue)
1912
1907
  {
1913
1908
  deregistration?.Invoke();
1914
1909
  }
@@ -1919,6 +1914,53 @@ namespace DxMessaging.Core
1919
1914
  _deregistrations?.Clear();
1920
1915
  }
1921
1916
 
1917
+ /// <summary>
1918
+ /// Retargets staged registrations to use a new message bus, re-registering active handlers if needed.
1919
+ /// </summary>
1920
+ /// <param name="messageBus">Bus override to apply. Pass <c>null</c> to resume using the handler default.</param>
1921
+ /// <param name="rebindMode">Determines whether existing registrations should move to the supplied bus immediately.</param>
1922
+ public void RetargetMessageBus(IMessageBus messageBus, MessageBusRebindMode rebindMode)
1923
+ {
1924
+ #pragma warning disable CS0618 // Type or member is obsolete
1925
+ MessageBusRebindMode effectiveMode =
1926
+ rebindMode == MessageBusRebindMode.Unknown
1927
+ #pragma warning restore CS0618 // Type or member is obsolete
1928
+ ? MessageBusRebindMode.RebindActive
1929
+ : rebindMode;
1930
+
1931
+ bool sameBus = ReferenceEquals(_messageBus, messageBus);
1932
+ bool rebindActiveRegistrations =
1933
+ effectiveMode == MessageBusRebindMode.RebindActive
1934
+ && _enabled
1935
+ && _deregistrations is { Count: > 0 };
1936
+ if (sameBus && !rebindActiveRegistrations)
1937
+ {
1938
+ return;
1939
+ }
1940
+
1941
+ if (rebindActiveRegistrations)
1942
+ {
1943
+ _actionQueue.Clear();
1944
+ _actionQueue.AddRange(_deregistrations.Values);
1945
+ foreach (Action deregistration in _actionQueue)
1946
+ {
1947
+ deregistration?.Invoke();
1948
+ }
1949
+ }
1950
+
1951
+ _messageBus = messageBus;
1952
+
1953
+ if (rebindActiveRegistrations && _registrations is { Count: > 0 })
1954
+ {
1955
+ _actionQueue.Clear();
1956
+ _actionQueue.AddRange(_registrations.Values);
1957
+ foreach (Action registration in _actionQueue)
1958
+ {
1959
+ registration?.Invoke();
1960
+ }
1961
+ }
1962
+ }
1963
+
1922
1964
  /// <summary>
1923
1965
  /// Removes a single staged registration by handle.
1924
1966
  /// </summary>
@@ -1951,7 +1993,7 @@ namespace DxMessaging.Core
1951
1993
  {
1952
1994
  private readonly MessageRegistrationToken _token;
1953
1995
  private readonly MessageRegistrationHandle _handle;
1954
- private int _disposed; // 0 = false, 1 = true (immutability-friendly pattern)
1996
+ private bool _valid;
1955
1997
 
1956
1998
  public RegistrationDisposable(
1957
1999
  MessageRegistrationToken token,
@@ -1960,18 +2002,18 @@ namespace DxMessaging.Core
1960
2002
  {
1961
2003
  _token = token;
1962
2004
  _handle = handle;
1963
- _disposed = 1;
2005
+ _valid = true;
1964
2006
  }
1965
2007
 
1966
2008
  public void Dispose()
1967
2009
  {
1968
2010
  // Best-effort idempotence; AsDisposable instances are short-lived and immutable
1969
- if (_disposed != 0)
2011
+ if (_valid)
1970
2012
  {
1971
2013
  _token.RemoveRegistration(_handle);
1972
2014
  }
1973
2015
 
1974
- _disposed = 0;
2016
+ _valid = false;
1975
2017
  }
1976
2018
  }
1977
2019
 
@@ -0,0 +1,31 @@
1
+ namespace DxMessaging.Unity
2
+ {
3
+ using DxMessaging.Core;
4
+ using DxMessaging.Core.MessageBus;
5
+ using UnityEngine;
6
+
7
+ /// <summary>
8
+ /// Serialized provider that returns the current global <see cref="MessageHandler.MessageBus"/> instance.
9
+ /// </summary>
10
+ /// <remarks>
11
+ /// This asset mirrors whatever bus is currently configured via <see cref="MessageHandler.SetGlobalMessageBus(IMessageBus)"/>.
12
+ /// Pair it with <see cref="InitialGlobalMessageBusProvider"/> when you need to compare the original and overridden buses.
13
+ /// </remarks>
14
+ /// <example>
15
+ /// <code>
16
+ /// // Configure a MessagingComponent at design time by dragging the asset into a MessagingComponentInstaller
17
+ /// messagingComponentInstaller.SetProvider(CurrentGlobalMessageBusProviderHandle);
18
+ /// </code>
19
+ /// </summary>
20
+ [CreateAssetMenu(
21
+ fileName = "CurrentGlobalMessageBusProvider",
22
+ menuName = "Wallstop Studios/DxMessaging/Message Bus Providers/Current Global Message Bus"
23
+ )]
24
+ public sealed class CurrentGlobalMessageBusProvider : ScriptableMessageBusProvider
25
+ {
26
+ public override IMessageBus Resolve()
27
+ {
28
+ return MessageHandler.MessageBus;
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,12 @@
1
+ fileFormatVersion: 2
2
+ guid: 689f1e1a8d9f4c34f9e3ab4e3f94ec37
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
12
+