com.wallstop-studios.dxmessaging 2.1.1 → 2.1.3

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 (158) hide show
  1. package/.github/workflows/dotnet-tests.yml +72 -0
  2. package/.lychee.toml +4 -2
  3. package/AGENTS.md +13 -12
  4. package/Docs/Comparisons.md +5 -5
  5. package/Docs/Install.md +2 -1
  6. package/Docs/InterceptorsAndOrdering.md +1 -1
  7. package/Docs/Performance.md +15 -13
  8. package/Docs/QuickReference.md +1 -1
  9. package/Docs/Reference.md +5 -5
  10. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  11. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +13 -2
  12. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll +0 -0
  13. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +11 -0
  14. package/Editor/Analyzers/System.Collections.Immutable.dll +0 -0
  15. package/Editor/Analyzers/System.Collections.Immutable.dll.meta +11 -0
  16. package/Editor/Analyzers/System.Reflection.Metadata.dll +0 -0
  17. package/Editor/Analyzers/System.Reflection.Metadata.dll.meta +13 -2
  18. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
  19. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +11 -0
  20. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
  21. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +3 -2
  22. package/Editor/AssemblyInfo.cs +3 -0
  23. package/Editor/AssemblyInfo.cs.meta +3 -0
  24. package/Editor/CustomEditors/MessagingComponentEditor.cs +24 -0
  25. package/Editor/DxMessagingEditorInitializer.cs +58 -1
  26. package/Editor/DxMessagingMenu.cs +38 -0
  27. package/Editor/DxMessagingMenu.cs.meta +11 -0
  28. package/Editor/DxMessagingSceneBuildProcessor.cs +81 -0
  29. package/Editor/DxMessagingSceneBuildProcessor.cs.meta +11 -0
  30. package/Editor/Settings/DxMessagingSettings.cs +37 -6
  31. package/Editor/Settings/DxMessagingSettingsProvider.cs +45 -7
  32. package/Editor/SetupCscRsp.cs +133 -53
  33. package/Editor/Testing/MessagingComponentEditorHarness.cs +218 -0
  34. package/Editor/Testing/MessagingComponentEditorHarness.cs.meta +3 -0
  35. package/Editor/Testing.meta +3 -0
  36. package/README.md +10 -4
  37. package/Runtime/AssemblyInfo.cs +1 -0
  38. package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +52 -0
  39. package/Runtime/Core/DataStructure/CyclicBuffer.cs +16 -0
  40. package/Runtime/Core/Diagnostics/MessageEmissionData.cs +27 -12
  41. package/Runtime/Core/Diagnostics/MessageRegistrationType.cs +62 -0
  42. package/Runtime/Core/DxMessagingStaticState.cs +108 -0
  43. package/Runtime/Core/DxMessagingStaticState.cs.meta +11 -0
  44. package/Runtime/Core/Extensions/IListExtensions.cs +24 -0
  45. package/Runtime/Core/Extensions/MessageBusExtensions.cs +144 -2
  46. package/Runtime/Core/Extensions/MessageExtensions.cs +2 -2
  47. package/Runtime/Core/Helper/MessageCache.cs +16 -0
  48. package/Runtime/Core/Helper/MessageHelperIndexer.cs +77 -0
  49. package/Runtime/Core/InstanceId.cs +91 -3
  50. package/Runtime/Core/MessageBus/DiagnosticsTarget.cs +31 -0
  51. package/Runtime/Core/MessageBus/DiagnosticsTarget.cs.meta +11 -0
  52. package/Runtime/Core/MessageBus/IMessageBus.cs +44 -16
  53. package/Runtime/Core/MessageBus/MessageBus.cs +96 -25
  54. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +46 -2
  55. package/Runtime/Core/MessageBus/MessagingRegistration.cs +63 -5
  56. package/Runtime/Core/MessageBus/RegistrationLog.cs +10 -0
  57. package/Runtime/Core/MessageHandler.cs +141 -8
  58. package/Runtime/Core/MessageRegistrationHandle.cs +59 -0
  59. package/Runtime/Core/MessageRegistrationToken.cs +20 -4
  60. package/Runtime/Core/Messages/ReflexiveMessage.cs +38 -0
  61. package/Runtime/Core/MessagingDebug.cs +16 -1
  62. package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs +6 -0
  63. package/Runtime/Unity/DxMessagingRuntimeInitializer.cs +19 -0
  64. package/Runtime/Unity/DxMessagingRuntimeInitializer.cs.meta +11 -0
  65. package/Runtime/Unity/InitialGlobalMessageBusProvider.cs +6 -0
  66. package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +19 -0
  67. package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +10 -0
  68. package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +14 -0
  69. package/Runtime/Unity/MessageAwareComponent.cs +2 -0
  70. package/Runtime/Unity/MessageBusProviderHandle.cs +4 -0
  71. package/Runtime/Unity/MessagingComponent.cs +109 -0
  72. package/Runtime/Unity/MessagingComponentInstaller.cs +2 -0
  73. package/Runtime/Unity/ScriptableMessageBusProvider.cs +2 -0
  74. package/Samples~/DI/README.md +13 -13
  75. package/Samples~/Mini Combat/README.md +15 -15
  76. package/Samples~/Mini Combat/Walkthrough.md +12 -12
  77. package/Samples~/UI Buttons + Inspector/README.md +4 -4
  78. package/SourceGenerators/Directory.Build.props +9 -0
  79. package/{Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj.meta → SourceGenerators/Directory.Build.props.meta} +1 -1
  80. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs +23 -24
  81. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs +91 -27
  82. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj +24 -4
  83. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DocsSnippetCompilationTests.cs +193 -0
  84. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DocsSnippetCompilationTests.cs.meta +11 -0
  85. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DxAutoConstructorGeneratorDiagnosticsTests.cs +69 -0
  86. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DxAutoConstructorGeneratorDiagnosticsTests.cs.meta +11 -0
  87. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DxMessageIdGeneratorDiagnosticsTests.cs +66 -0
  88. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DxMessageIdGeneratorDiagnosticsTests.cs.meta +11 -0
  89. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/GeneratorTestUtilities.cs +155 -0
  90. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/GeneratorTestUtilities.cs.meta +11 -0
  91. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/WallstopStudios.DxMessaging.SourceGenerators.Tests.csproj +20 -0
  92. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/WallstopStudios.DxMessaging.SourceGenerators.Tests.csproj.meta +7 -0
  93. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests.meta +8 -0
  94. package/Tests/Editor/MessagingComponentEditorHarnessTests.cs +243 -0
  95. package/Tests/Editor/MessagingComponentEditorHarnessTests.cs.meta +3 -0
  96. package/Tests/Editor/MessagingComponentSerializationTests.cs +129 -0
  97. package/Tests/Editor/MessagingComponentSerializationTests.cs.meta +3 -0
  98. package/Tests/Editor/WallstopStudios.DxMessaging.Tests.Editor.asmdef +19 -0
  99. package/Tests/Editor/WallstopStudios.DxMessaging.Tests.Editor.asmdef.meta +3 -0
  100. package/Tests/Editor.meta +3 -0
  101. package/Tests/Runtime/Benchmarks/BenchmarkSession.cs +3 -0
  102. package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs +3 -0
  103. package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs +3 -0
  104. package/Tests/Runtime/Benchmarks/PerformanceTests.cs +137 -0
  105. package/Tests/Runtime/Core/AlternateBusTests.cs +3 -0
  106. package/Tests/Runtime/Core/BroadcastTests.cs +3 -0
  107. package/Tests/Runtime/Core/CyclicBufferTests.cs +3 -0
  108. package/Tests/Runtime/Core/DefaultBusFallbackTests.cs +5 -2
  109. package/Tests/Runtime/Core/DiagnosticsTests.cs +6 -3
  110. package/Tests/Runtime/Core/DxMessagingStaticStateTests.cs +69 -0
  111. package/Tests/Runtime/Core/DxMessagingStaticStateTests.cs.meta +11 -0
  112. package/Tests/Runtime/Core/EdgeCaseTests.cs +3 -0
  113. package/Tests/Runtime/Core/EnablementTests.cs +3 -0
  114. package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs +2 -2
  115. package/Tests/Runtime/Core/GenericMessageTests.cs +3 -0
  116. package/Tests/Runtime/Core/GlobalAcceptAllTests.cs +3 -0
  117. package/Tests/Runtime/Core/InterceptorCancellationTests.cs +3 -0
  118. package/Tests/Runtime/Core/LifecycleTests.cs +3 -0
  119. package/Tests/Runtime/Core/MessageEmissionDataTests.cs +70 -0
  120. package/Tests/Runtime/Core/MessageEmissionDataTests.cs.meta +11 -0
  121. package/Tests/Runtime/Core/MessagingComponentLifecycleTests.cs +3 -0
  122. package/Tests/Runtime/Core/MessagingTestBase.cs +3 -0
  123. package/Tests/Runtime/Core/MutationDedupeTests.cs +3 -0
  124. package/Tests/Runtime/Core/MutationDestructionTests.cs +3 -0
  125. package/Tests/Runtime/Core/MutationDuringEmissionTests.cs +3 -0
  126. package/Tests/Runtime/Core/MutationGlobalAddTests.cs +3 -0
  127. package/Tests/Runtime/Core/MutationInterceptorTests.cs +3 -0
  128. package/Tests/Runtime/Core/MutationPostProcessorAcrossHandlersTests.cs +3 -0
  129. package/Tests/Runtime/Core/MutationPostProcessorMoreTests.cs +3 -0
  130. package/Tests/Runtime/Core/MutationPriorityTests.cs +3 -0
  131. package/Tests/Runtime/Core/NominalTests.cs +3 -0
  132. package/Tests/Runtime/Core/OrderingTests.cs +3 -0
  133. package/Tests/Runtime/Core/OverDeregistrationTests.cs +3 -0
  134. package/Tests/Runtime/Core/PostProcessorTests.cs +3 -0
  135. package/Tests/Runtime/Core/ReflexiveErrorTests.cs +3 -0
  136. package/Tests/Runtime/Core/ReflexiveMessageWarningTests.cs +4 -1
  137. package/Tests/Runtime/Core/ReflexiveTests.cs +3 -0
  138. package/Tests/Runtime/Core/RegistrationTests.cs +3 -0
  139. package/Tests/Runtime/Core/StringShorthandTests.cs +3 -0
  140. package/Tests/Runtime/Core/TargetedTests.cs +3 -0
  141. package/Tests/Runtime/Core/TypedShorthandTests.cs +3 -0
  142. package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs +3 -0
  143. package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +14 -78
  144. package/Tests/Runtime/Core/UntargetedTests.cs +3 -0
  145. package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs +4 -1
  146. package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs +3 -0
  147. package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs +3 -0
  148. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +3 -0
  149. package/Tests/Runtime/Scripts/Components/ManualListenerComponent.cs +3 -0
  150. package/Tests/Runtime/Scripts/Components/ReflexiveReceiverComponent.cs +3 -0
  151. package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs +3 -0
  152. package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs +3 -0
  153. package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs +87 -3
  154. package/Tests/Runtime/Unity/MessagingComponentInstallerSceneTests.cs +109 -0
  155. package/Tests/Runtime/Unity/MessagingComponentInstallerSceneTests.cs.meta +11 -0
  156. package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs +159 -17
  157. package/package.json +1 -1
  158. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj +0 -7
@@ -1,3 +1,4 @@
1
+ #if UNITY_2021_3_OR_NEWER
1
2
  namespace DxMessaging.Unity.Integrations.Reflex
2
3
  {
3
4
  #if REFLEX_PRESENT
@@ -10,6 +11,10 @@ namespace DxMessaging.Unity.Integrations.Reflex
10
11
  /// </summary>
11
12
  public sealed class DxMessagingRegistrationInstaller : IInstaller
12
13
  {
14
+ /// <summary>
15
+ /// Registers the DxMessaging builder services within the Reflex container.
16
+ /// </summary>
17
+ /// <param name="containerBuilder">Container builder receiving the registrations.</param>
13
18
  public void InstallBindings(ContainerBuilder containerBuilder)
14
19
  {
15
20
  containerBuilder.AddSingleton(
@@ -24,6 +29,11 @@ namespace DxMessaging.Unity.Integrations.Reflex
24
29
  [Inject]
25
30
  private Container _container;
26
31
 
32
+ /// <summary>
33
+ /// Builds a leasing wrapper using the container-aware provider resolution logic.
34
+ /// </summary>
35
+ /// <param name="options">Build options provided by the caller.</param>
36
+ /// <returns>Lease produced by the underlying <see cref="MessageRegistrationBuilder"/>.</returns>
27
37
  public MessageRegistrationLease Build(MessageRegistrationBuildOptions options)
28
38
  {
29
39
  MessageRegistrationBuilder innerBuilder = ResolveInnerBuilder();
@@ -58,11 +68,19 @@ namespace DxMessaging.Unity.Integrations.Reflex
58
68
  {
59
69
  private readonly Container _container;
60
70
 
71
+ /// <summary>
72
+ /// Wraps a Reflex container as an <see cref="IMessageBusProvider"/>.
73
+ /// </summary>
74
+ /// <param name="container">Container used to resolve <see cref="IMessageBus"/> instances.</param>
61
75
  public ContainerMessageBusProvider(Container container)
62
76
  {
63
77
  _container = container;
64
78
  }
65
79
 
80
+ /// <summary>
81
+ /// Resolves an <see cref="IMessageBus"/> from the underlying container.
82
+ /// </summary>
83
+ /// <returns>Message bus resolved from Reflex.</returns>
66
84
  public IMessageBus Resolve()
67
85
  {
68
86
  return _container.Resolve<IMessageBus>();
@@ -71,3 +89,4 @@ namespace DxMessaging.Unity.Integrations.Reflex
71
89
  }
72
90
  #endif
73
91
  }
92
+ #endif
@@ -1,3 +1,4 @@
1
+ #if UNITY_2021_3_OR_NEWER
1
2
  namespace DxMessaging.Unity.Integrations.VContainer
2
3
  {
3
4
  #if VCONTAINER_PRESENT
@@ -31,11 +32,19 @@ namespace DxMessaging.Unity.Integrations.VContainer
31
32
  {
32
33
  private readonly IObjectResolver _resolver;
33
34
 
35
+ /// <summary>
36
+ /// Wraps a VContainer resolver as an <see cref="IMessageBusProvider"/>.
37
+ /// </summary>
38
+ /// <param name="resolver">Resolver used to obtain <see cref="IMessageBus"/> instances.</param>
34
39
  public ResolverMessageBusProvider(IObjectResolver resolver)
35
40
  {
36
41
  _resolver = resolver;
37
42
  }
38
43
 
44
+ /// <summary>
45
+ /// Resolves an <see cref="IMessageBus"/> from the current VContainer scope.
46
+ /// </summary>
47
+ /// <returns>Scoped message bus.</returns>
39
48
  public IMessageBus Resolve()
40
49
  {
41
50
  return _resolver.Resolve<IMessageBus>();
@@ -44,3 +53,4 @@ namespace DxMessaging.Unity.Integrations.VContainer
44
53
  }
45
54
  #endif
46
55
  }
56
+ #endif
@@ -1,3 +1,4 @@
1
+ #if UNITY_2021_3_OR_NEWER
1
2
  namespace DxMessaging.Unity.Integrations.Zenject
2
3
  {
3
4
  #if ZENJECT_PRESENT
@@ -15,6 +16,9 @@ namespace DxMessaging.Unity.Integrations.Zenject
15
16
  InstallBindings();
16
17
  }
17
18
 
19
+ /// <summary>
20
+ /// Registers the DxMessaging builder within the Zenject container.
21
+ /// </summary>
18
22
  public override void InstallBindings()
19
23
  {
20
24
  Container.Bind<IMessageRegistrationBuilder>().FromMethod(CreateBuilder).AsTransient();
@@ -39,12 +43,21 @@ namespace DxMessaging.Unity.Integrations.Zenject
39
43
  private readonly DiContainer _container;
40
44
  private readonly IMessageBus _cachedBus;
41
45
 
46
+ /// <summary>
47
+ /// Creates a provider that uses the container-supplied bus, falling back to resolving on demand.
48
+ /// </summary>
49
+ /// <param name="container">Zenject container used to resolve services.</param>
50
+ /// <param name="cachedBus">Cached bus instance to return if available.</param>
42
51
  public ContainerMessageBusProvider(DiContainer container, IMessageBus cachedBus)
43
52
  {
44
53
  _container = container;
45
54
  _cachedBus = cachedBus;
46
55
  }
47
56
 
57
+ /// <summary>
58
+ /// Resolves the message bus for the current scope.
59
+ /// </summary>
60
+ /// <returns>Cached bus if provided; otherwise resolves from the container.</returns>
48
61
  public IMessageBus Resolve()
49
62
  {
50
63
  return _cachedBus ?? _container.Resolve<IMessageBus>();
@@ -53,3 +66,4 @@ namespace DxMessaging.Unity.Integrations.Zenject
53
66
  }
54
67
  #endif
55
68
  }
69
+ #endif
@@ -1,3 +1,4 @@
1
+ #if UNITY_2021_3_OR_NEWER
1
2
  namespace DxMessaging.Unity
2
3
  {
3
4
  using Core;
@@ -273,3 +274,4 @@ namespace DxMessaging.Unity
273
274
  }
274
275
  }
275
276
  }
277
+ #endif
@@ -1,3 +1,4 @@
1
+ #if UNITY_2021_3_OR_NEWER
1
2
  namespace DxMessaging.Unity
2
3
  {
3
4
  using System;
@@ -18,6 +19,8 @@ namespace DxMessaging.Unity
18
19
  [NonSerialized]
19
20
  private IMessageBusProvider _runtimeProvider;
20
21
 
22
+ internal ScriptableMessageBusProvider SerializedProvider => _provider;
23
+
21
24
  /// <summary>
22
25
  /// Initializes a new instance referencing the supplied provider asset.
23
26
  /// </summary>
@@ -95,3 +98,4 @@ namespace DxMessaging.Unity
95
98
  }
96
99
  }
97
100
  }
101
+ #endif
@@ -1,7 +1,9 @@
1
+ #if UNITY_2021_3_OR_NEWER
1
2
  namespace DxMessaging.Unity
2
3
  {
3
4
  using System;
4
5
  using System.Collections.Generic;
6
+ using System.Linq;
5
7
  using Core;
6
8
  using Core.MessageBus;
7
9
  using UnityEngine;
@@ -44,6 +46,20 @@ namespace DxMessaging.Unity
44
46
  internal readonly Dictionary<MonoBehaviour, MessageRegistrationToken> _registeredListeners =
45
47
  new();
46
48
 
49
+ internal bool AutoConfigureSerializedProviderOnAwake =>
50
+ autoConfigureSerializedProviderOnAwake;
51
+
52
+ internal bool HasRuntimeProvider => _messageBusProvider != null;
53
+
54
+ internal bool HasMessageBusOverride => _messageBusOverride != null;
55
+
56
+ internal bool HasSerializedProvider => _serializedProviderHandle.TryGetProvider(out _);
57
+
58
+ internal MessageBusProviderHandle SerializedProviderHandle => _serializedProviderHandle;
59
+
60
+ internal ScriptableMessageBusProvider SerializedProviderAsset =>
61
+ _serializedProviderHandle.SerializedProvider;
62
+
47
63
  /// <summary>
48
64
  /// Creates a <see cref="IMessageRegistrationBuilder"/> aligned with this component's configured bus or provider.
49
65
  /// </summary>
@@ -311,5 +327,98 @@ namespace DxMessaging.Unity
311
327
 
312
328
  return null;
313
329
  }
330
+
331
+ #if UNITY_EDITOR
332
+ [ContextMenu("DxMessaging/Dump Registrations")]
333
+ private void ContextDumpRegistrations()
334
+ {
335
+ DumpRegistrations();
336
+ }
337
+
338
+ internal void DumpRegistrations()
339
+ {
340
+ if (_registeredListeners.Count == 0)
341
+ {
342
+ Debug.Log($"[DxMessaging] {name} has no registered listeners.");
343
+ return;
344
+ }
345
+
346
+ foreach (
347
+ KeyValuePair<MonoBehaviour, MessageRegistrationToken> pair in _registeredListeners
348
+ )
349
+ {
350
+ MonoBehaviour listener = pair.Key;
351
+ MessageRegistrationToken token = pair.Value;
352
+ Debug.Log(
353
+ $"[DxMessaging] Listener '{listener}' (Enabled: {token.Enabled}, Diagnostic: {token.DiagnosticMode}) "
354
+ + $"with {token._metadata.Count} registrations on '{name}'."
355
+ );
356
+ }
357
+ }
358
+
359
+ [ContextMenu("DxMessaging/Reset Runtime State")]
360
+ private void ContextResetRuntimeState()
361
+ {
362
+ if (EditorResetRuntimeState())
363
+ {
364
+ Debug.Log($"[DxMessaging] Cleared runtime state for '{name}'.");
365
+ }
366
+ else
367
+ {
368
+ Debug.Log($"[DxMessaging] No runtime state to clear on '{name}'.");
369
+ }
370
+ }
371
+
372
+ internal bool EditorResetRuntimeState()
373
+ {
374
+ bool cleared = false;
375
+
376
+ if (_registeredListeners.Count > 0)
377
+ {
378
+ foreach (MessageRegistrationToken token in _registeredListeners.Values.ToArray())
379
+ {
380
+ try
381
+ {
382
+ if (token.Enabled)
383
+ {
384
+ token.Disable();
385
+ }
386
+
387
+ token.Dispose();
388
+ }
389
+ catch (Exception exception)
390
+ {
391
+ Debug.LogWarning(
392
+ $"[DxMessaging] Disposing stale token on {name} failed. {exception}"
393
+ );
394
+ }
395
+ }
396
+
397
+ _registeredListeners.Clear();
398
+ cleared = true;
399
+ }
400
+
401
+ if (_messageHandler != null)
402
+ {
403
+ _messageHandler = null;
404
+ cleared = true;
405
+ }
406
+
407
+ if (_messageBusOverride != null)
408
+ {
409
+ _messageBusOverride = null;
410
+ cleared = true;
411
+ }
412
+
413
+ if (_messageBusProvider != null)
414
+ {
415
+ _messageBusProvider = null;
416
+ cleared = true;
417
+ }
418
+
419
+ return cleared;
420
+ }
421
+ #endif
314
422
  }
315
423
  }
424
+ #endif
@@ -1,3 +1,4 @@
1
+ #if UNITY_2021_3_OR_NEWER
1
2
  namespace DxMessaging.Unity
2
3
  {
3
4
  using System.Collections.Generic;
@@ -118,3 +119,4 @@ namespace DxMessaging.Unity
118
119
  }
119
120
  }
120
121
  }
122
+ #endif
@@ -1,3 +1,4 @@
1
+ #if UNITY_2021_3_OR_NEWER
1
2
  namespace DxMessaging.Unity
2
3
  {
3
4
  using DxMessaging.Core.MessageBus;
@@ -12,3 +13,4 @@ namespace DxMessaging.Unity
12
13
  public abstract IMessageBus Resolve();
13
14
  }
14
15
  }
16
+ #endif
@@ -13,18 +13,18 @@ These snippets illustrate how to consume `IMessageRegistrationBuilder` inside co
13
13
 
14
14
  Each sample shows:
15
15
 
16
- - Registering `IMessageRegistrationBuilder` via the provided shim under `Runtime/Unity/Integrations/`.
16
+ - Registering `IMessageRegistrationBuilder` via the provided shim under [Runtime/Unity/Integrations](../../Runtime/Unity/Integrations/).
17
17
  - Constructing a `MessageRegistrationLease` in a container-managed service.
18
18
  - Activating/deactivating the lease using the container lifecycle.
19
19
 
20
20
  ### Structure
21
21
 
22
- - `Zenject/SampleInstaller.cs`
23
- - `VContainer/SampleLifetimeScope.cs`
24
- - `Reflex/SampleInstaller.cs`
25
- - `Providers/CurrentGlobalMessageBusProvider.asset` — ScriptableObject that resolves whichever bus is currently configured as global.
26
- - `Providers/InitialGlobalMessageBusProvider.asset` — ScriptableObject that always returns the original startup global bus, ignoring later overrides.
27
- - `Prefabs/MessagingInstallerSample.prefab` — ready-to-use hierarchy with `MessagingComponentInstaller` configuring a child `MessagingComponent` using the provider asset. Drop it into a scene to see provider-driven wiring without writing setup code.
22
+ - Zenject sample installer: [SampleInstaller.cs](./Zenject/SampleInstaller.cs)
23
+ - VContainer sample lifetime scope: [SampleLifetimeScope.cs](./VContainer/SampleLifetimeScope.cs)
24
+ - Reflex sample installer: [SampleInstaller.cs](./Reflex/SampleInstaller.cs)
25
+ - Current global message bus provider asset: [CurrentGlobalMessageBusProvider.asset](./Providers/CurrentGlobalMessageBusProvider.asset) — ScriptableObject that resolves whichever bus is currently configured as global.
26
+ - Initial global message bus provider asset: [InitialGlobalMessageBusProvider.asset](./Providers/InitialGlobalMessageBusProvider.asset) — ScriptableObject that always returns the original startup global bus, ignoring later overrides.
27
+ - Prefab setup: [MessagingInstallerSample.prefab](./Prefabs/MessagingInstallerSample.prefab) — ready-to-use hierarchy with `MessagingComponentInstaller` configuring a child `MessagingComponent` using the provider asset. Drop it into a scene to see provider-driven wiring without writing setup code.
28
28
 
29
29
  ## Walkthrough
30
30
 
@@ -33,19 +33,19 @@ Each sample shows:
33
33
 
34
34
  2. **Hook up the container**
35
35
  - **Zenject**:
36
- - Add `DxMessagingRegistrationInstaller` (from `Runtime/Unity/Integrations/`) to your ProjectContext or scene installer list.
37
- - Drop `Zenject/SampleInstaller.cs` into your project and register it alongside other installers. When the scene runs, the installer resolves `IMessageRegistrationBuilder`, stages a `PlayerSpawned` listener, and activates via the Zenject lifecycle.
36
+ - Add `DxMessagingRegistrationInstaller` (from [Runtime/Unity/Integrations](../../Runtime/Unity/Integrations/)) to your ProjectContext or scene installer list.
37
+ - Drop [SampleInstaller.cs](./Zenject/SampleInstaller.cs) into your project and register it alongside other installers. When the scene runs, the installer resolves `IMessageRegistrationBuilder`, stages a `PlayerSpawned` listener, and activates via the Zenject lifecycle.
38
38
  - **VContainer**:
39
- - Define `VCONTAINER_PRESENT` and reference the optional extension under `Runtime/Unity/Integrations/VContainerRegistrationExtensions.cs`.
40
- - Add `VContainer/SampleLifetimeScope` to the scene (or derive from it); the sample scope registers the builder and an entry point that emits/consumes `ScoreUpdated` messages each tick.
39
+ - Define `VCONTAINER_PRESENT` and reference the optional extension under [VContainerRegistrationExtensions.cs](../../Runtime/Unity/Integrations/VContainerRegistrationExtensions.cs).
40
+ - Add [SampleLifetimeScope.cs](./VContainer/SampleLifetimeScope.cs) to the scene (or derive from it); the sample scope registers the builder and an entry point that emits/consumes `ScoreUpdated` messages each tick.
41
41
  - **Reflex**:
42
42
  - Enable `REFLEX_PRESENT` and install `DxMessagingRegistrationInstaller` into your container bootstrap.
43
- - Include `Reflex/SampleInstaller` in your installer chain. The sample service resolves `IMessageRegistrationBuilder`, subscribes to `PlayerAlert`, and can emit alerts via `EmitAlertFor`.
43
+ - Include [SampleInstaller.cs](./Reflex/SampleInstaller.cs) in your installer chain. The sample service resolves `IMessageRegistrationBuilder`, subscribes to `PlayerAlert`, and can emit alerts via `EmitAlertFor`.
44
44
 
45
45
  3. **Emit a message**
46
46
  Use the service exposed by the container (e.g., call into `ScoreboardService` or `PlayerAlertService`) to emit a message. Because the prefab already configured `MessagingComponent` instances via the installer, the listeners run immediately.
47
47
 
48
48
  4. **Swap providers** (optional)
49
- Duplicate `Providers/CurrentGlobalMessageBusProvider.asset`, modify it to return a custom bus, assign it on the prefab root, and observe how builder-created leases now resolve that bus instead.
49
+ Duplicate [CurrentGlobalMessageBusProvider.asset](./Providers/CurrentGlobalMessageBusProvider.asset), modify it to return a custom bus, assign it on the prefab root, and observe how builder-created leases now resolve that bus instead.
50
50
 
51
51
  Feel free to duplicate these scripts into your own project and adjust lifecycles or message types as needed.
@@ -83,11 +83,11 @@ Here's what each script does:
83
83
 
84
84
  | File | Purpose | Message Type |
85
85
  |------|---------|--------------|
86
- | **Messages.cs** | Defines all message types | Contains `VideoSettingsChanged`, `Heal`, and `TookDamage` |
87
- | **Player.cs** | Handles receiving healing | Listens for `Heal` (Targeted) |
88
- | **Enemy.cs** | Announces when damaged | Emits `TookDamage` (Broadcast) |
89
- | **UIOverlay.cs** | Updates UI based on events | Listens to settings and `TookDamage` (Broadcast) |
90
- | **Boot.cs** | Starts the demo | Simulates message flow |
86
+ | **[Messages.cs](./Messages.cs)** | Defines all message types | Contains `VideoSettingsChanged`, `Heal`, and `TookDamage` |
87
+ | **[Player.cs](./Player.cs)** | Handles receiving healing | Listens for `Heal` (Targeted) |
88
+ | **[Enemy.cs](./Enemy.cs)** | Announces when damaged | Emits `TookDamage` (Broadcast) |
89
+ | **[UIOverlay.cs](./UIOverlay.cs)** | Updates UI based on events | Listens to settings and `TookDamage` (Broadcast) |
90
+ | **[Boot.cs](./Boot.cs)** | Starts the demo | Simulates message flow |
91
91
 
92
92
  ---
93
93
 
@@ -126,10 +126,10 @@ For **each GameObject**, you need TWO components:
126
126
  - Click GameObject → Add Component → "MessagingComponent"
127
127
 
128
128
  1. **Add the sample script**:
129
- - **Player** GameObject → Add `Player.cs` script
130
- - **Enemy** GameObject → Add `Enemy.cs` script
131
- - **UIOverlay** GameObject → Add `UIOverlay.cs` script
132
- - **Boot** GameObject → Add `Boot.cs` script
129
+ - **Player** GameObject → Add [Player.cs](./Player.cs) script
130
+ - **Enemy** GameObject → Add [Enemy.cs](./Enemy.cs) script
131
+ - **UIOverlay** GameObject → Add [UIOverlay.cs](./UIOverlay.cs) script
132
+ - **Boot** GameObject → Add [Boot.cs](./Boot.cs) script
133
133
 
134
134
  #### Step 3: Run and Observe
135
135
 
@@ -147,11 +147,11 @@ Press Play! The Boot script will automatically:
147
147
 
148
148
  ### The Message Flow
149
149
 
150
- #### Boot.cs sends messages:
150
+ #### [Boot.cs](./Boot.cs) sends messages:
151
151
 
152
- 1. `VideoSettingsChanged` (Untargeted) → UIOverlay.cs receives
153
- 2. `Heal` (Targeted to Player) → Player.cs receives
154
- 3. `TookDamage` (Broadcast from Enemy) → UIOverlay.cs receives
152
+ 1. `VideoSettingsChanged` (Untargeted) → [UIOverlay.cs](./UIOverlay.cs) receives
153
+ 2. `Heal` (Targeted to Player) → [Player.cs](./Player.cs) receives
154
+ 3. `TookDamage` (Broadcast from Enemy) → [UIOverlay.cs](./UIOverlay.cs) receives
155
155
 
156
156
  ### Understanding Message Types
157
157
 
@@ -318,6 +318,6 @@ protected override void OnEnable() {
318
318
  ## Quick Reference
319
319
 
320
320
  **Enable Diagnostics**: Select MessagingComponent in Inspector → Enable Diagnostics
321
- **Message Types**: See `Messages.cs` for all available messages
322
- **Modify Behavior**: Edit handler methods in Player.cs, Enemy.cs, or UIOverlay.cs
321
+ **Message Types**: See [Messages.cs](./Messages.cs) for all available messages
322
+ **Modify Behavior**: Edit handler methods in [Player.cs](./Player.cs), [Enemy.cs](./Enemy.cs), or [UIOverlay.cs](./UIOverlay.cs)
323
323
  **Extend Scripts**: Always call `base.RegisterMessageHandlers()` and other `base.*` methods
@@ -17,7 +17,7 @@
17
17
  After reading this walkthrough, you'll know:
18
18
 
19
19
  1. **Why each message type was chosen** - the reasoning behind Untargeted vs Targeted vs Broadcast
20
- 2. **How the code flows** - step-by-step from Boot.cs through every script
20
+ 2. **How the code flows** - step-by-step from [Boot.cs](./Boot.cs) through every script
21
21
  3. **Common patterns** - Observer, Broadcaster, Orchestrator, and more
22
22
  4. **Debugging strategies** - how to find and fix issues
23
23
  5. **How to extend it** - add your own messages and handlers
@@ -43,7 +43,7 @@ After reading this walkthrough, you'll know:
43
43
 
44
44
  Let's understand what each script does:
45
45
 
46
- ### Messages.cs
46
+ ### [Messages.cs](./Messages.cs)
47
47
 
48
48
  **Purpose**: Defines all message types used in the sample
49
49
 
@@ -56,7 +56,7 @@ Let's understand what each script does:
56
56
 
57
57
  **Why separate file?** Keeping messages in one place makes them easy to find and prevents circular dependencies.
58
58
 
59
- ### Player.cs
59
+ ### [Player.cs](./Player.cs)
60
60
 
61
61
  **What it does**: Listens for healing messages targeted specifically at this player
62
62
 
@@ -68,7 +68,7 @@ Let's understand what each script does:
68
68
 
69
69
  **Real-world analogy**: Like having your name called in a doctor's office—only you respond.
70
70
 
71
- ### Enemy.cs
71
+ ### [Enemy.cs](./Enemy.cs)
72
72
 
73
73
  **What it does**: Broadcasts when it takes damage
74
74
 
@@ -80,7 +80,7 @@ Let's understand what each script does:
80
80
 
81
81
  **Real-world analogy**: Like ringing a bell—anyone nearby can hear it.
82
82
 
83
- ### UIOverlay.cs
83
+ ### [UIOverlay.cs](./UIOverlay.cs)
84
84
 
85
85
  **What it does**: Monitors game events and updates the UI
86
86
 
@@ -92,7 +92,7 @@ Let's understand what each script does:
92
92
 
93
93
  **Real-world analogy**: Like a news reporter watching everything and reporting it.
94
94
 
95
- ### Boot.cs
95
+ ### [Boot.cs](./Boot.cs)
96
96
 
97
97
  **What it does**: Starts the demo by simulating a sequence of events
98
98
 
@@ -141,8 +141,8 @@ Settings changes are **global events**—they don't target anyone specifically.
141
141
 
142
142
  ### The Code Flow
143
143
 
144
- 1. **Boot.cs** calls: `MessageHub.Publish(new VideoSettingsChanged())`
145
- 1. **UIOverlay.cs** receives it through its registered handler
144
+ 1. **[Boot.cs](./Boot.cs)** calls: `MessageHub.Publish(new VideoSettingsChanged())`
145
+ 1. **[UIOverlay.cs](./UIOverlay.cs)** receives it through its registered handler
146
146
  1. **UIOverlay** rebuilds the UI with new settings
147
147
 
148
148
  ### Developer Notes
@@ -178,9 +178,9 @@ We want to heal **one specific player**, not all players in the scene.
178
178
 
179
179
  ### The Code Flow
180
180
 
181
- 1. **Boot.cs** finds the Player Component reference
182
- 1. **Boot.cs** calls: `MessageHub.Publish(new Heal(amount), targetComponent)`
183
- 1. **Only the targeted Player.cs** receives it through its handler
181
+ 1. **[Boot.cs](./Boot.cs)** finds the Player Component reference
182
+ 1. **[Boot.cs](./Boot.cs)** calls: `MessageHub.Publish(new Heal(amount), targetComponent)`
183
+ 1. **Only the targeted [Player.cs](./Player.cs)** receives it through its handler
184
184
  1. **Player** increases its HP
185
185
 
186
186
  ### Developer Notes
@@ -216,7 +216,7 @@ The Enemy doesn't know (or care) who needs to know about the damage. It just ann
216
216
 
217
217
  ### The Code Flow
218
218
 
219
- 1. **Enemy.cs** detects it took damage
219
+ 1. **[Enemy.cs](./Enemy.cs)** detects it took damage
220
220
  1. **Enemy** calls: `this.EmitBroadcast(new TookDamage(amount))`
221
221
  1. **UIOverlay** receives it via `RegisterBroadcastWithoutSource`
222
222
  1. **UIOverlay** displays the damage event
@@ -120,7 +120,7 @@ MessageHandler.MessageBus.DiagnosticsMode = true;
120
120
 
121
121
  - Multiple buttons: Add more UI Buttons, add more `UIButtonEmitter`s, and give each a unique `buttonId`.
122
122
  - Targeted vs. untargeted: Notice the sample also sends a targeted `StringMessage` to the emitter’s `gameObject`.
123
- - Your own message type: Open `Messages.cs` to see how `ButtonClicked` is declared using attributes:
123
+ - Your own message type: Open [Messages.cs](./Messages.cs) to see how `ButtonClicked` is declared using attributes:
124
124
 
125
125
  ```csharp
126
126
  [DxUntargetedMessage]
@@ -202,8 +202,8 @@ public class MyObserver : MessageAwareComponent {
202
202
 
203
203
  ## Next Steps
204
204
 
205
- - Quick tour: `Docs/GettingStarted.md`
206
- - Patterns and recipes: `Docs/Patterns.md`
207
- - Explore another sample: `../Mini%20Combat/README.md`
205
+ - Quick tour: [Getting Started guide](../../Docs/GettingStarted.md)
206
+ - Patterns and recipes: [Common Patterns](../../Docs/Patterns.md)
207
+ - Explore another sample: [Mini Combat sample](../Mini%20Combat/README.md)
208
208
 
209
209
  You now have an easy, inspector-first way to publish and observe messages. Build up from here by swapping in your own message types and listeners.
@@ -0,0 +1,9 @@
1
+ <Project>
2
+ <PropertyGroup Condition="'$(MSBuildProjectName)' == 'WallstopStudios.DxMessaging.SourceGenerators.Tests'">
3
+ <SolutionDir Condition="'$(SolutionDir)' == ''">$(MSBuildThisFileDirectory)..\</SolutionDir>
4
+ <ArtifactsRoot>$(SolutionDir).artifacts/SourceGenerators.Tests/</ArtifactsRoot>
5
+ <IntermediateOutputPath>$(ArtifactsRoot)obj/$(Configuration)/</IntermediateOutputPath>
6
+ <OutputPath>$(ArtifactsRoot)bin/$(Configuration)/</OutputPath>
7
+ <VSTestResultsDirectory>$(ArtifactsRoot)TestResults/</VSTestResultsDirectory>
8
+ </PropertyGroup>
9
+ </Project>
@@ -1,5 +1,5 @@
1
1
  fileFormatVersion: 2
2
- guid: 939c668fdbd24a74591e482310e0e40f
2
+ guid: 5b80e1cf4c3c72a43bbd48e4667f00f7
3
3
  DefaultImporter:
4
4
  externalObjects: {}
5
5
  userData: