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
@@ -0,0 +1,218 @@
1
+ #if UNITY_EDITOR
2
+ namespace DxMessaging.Editor.Testing
3
+ {
4
+ using System;
5
+ using System.Collections.Generic;
6
+ using System.Linq;
7
+ using Core;
8
+ using Core.Diagnostics;
9
+ using Core.MessageBus;
10
+ using Unity;
11
+ using UnityEngine;
12
+
13
+ /// <summary>
14
+ /// Captures inspector-oriented diagnostics for <see cref="MessagingComponent"/> instances without relying on GUI APIs.
15
+ /// Intended for automated editor tests that need to validate inspector state transitions.
16
+ /// </summary>
17
+ internal static class MessagingComponentEditorHarness
18
+ {
19
+ private static readonly MessageEmissionData[] EmptyEmissions =
20
+ Array.Empty<MessageEmissionData>();
21
+
22
+ internal static MessagingComponentInspectorState Capture(MessagingComponent component)
23
+ {
24
+ if (component == null)
25
+ {
26
+ throw new ArgumentNullException(nameof(component));
27
+ }
28
+
29
+ bool globalDiagnosticsEnabled = false;
30
+ IReadOnlyList<MessageEmissionData> globalHistory = EmptyEmissions;
31
+
32
+ if (MessageHandler.MessageBus is MessageBus concreteBus)
33
+ {
34
+ globalDiagnosticsEnabled = concreteBus.DiagnosticsMode;
35
+ if (globalDiagnosticsEnabled && concreteBus._emissionBuffer.Count > 0)
36
+ {
37
+ globalHistory = concreteBus._emissionBuffer.ToArray();
38
+ }
39
+ }
40
+
41
+ List<ListenerDiagnosticsView> listenerViews = component
42
+ ._registeredListeners.OrderBy(pair => pair.Key.GetInstanceID())
43
+ .Select(pair => CreateListenerView(pair.Key, pair.Value))
44
+ .ToList();
45
+
46
+ ProviderDiagnosticsView providerDiagnostics = CreateProviderDiagnostics(component);
47
+
48
+ return new MessagingComponentInspectorState(
49
+ globalDiagnosticsEnabled,
50
+ globalHistory,
51
+ listenerViews,
52
+ providerDiagnostics
53
+ );
54
+ }
55
+
56
+ private static ListenerDiagnosticsView CreateListenerView(
57
+ MonoBehaviour listener,
58
+ MessageRegistrationToken token
59
+ )
60
+ {
61
+ MessageRegistrationView[] registrations = token
62
+ ._metadata.OrderBy(pair => pair.Key)
63
+ .Select(pair => new MessageRegistrationView(
64
+ pair.Key,
65
+ pair.Value,
66
+ token._callCounts.TryGetValue(pair.Key, out int callCount) ? callCount : 0
67
+ ))
68
+ .ToArray();
69
+
70
+ IReadOnlyList<MessageEmissionData> emissionHistory =
71
+ token._emissionBuffer.Count > 0 ? token._emissionBuffer.ToArray() : EmptyEmissions;
72
+
73
+ return new ListenerDiagnosticsView(
74
+ listener,
75
+ token.DiagnosticMode,
76
+ token.Enabled,
77
+ registrations,
78
+ emissionHistory
79
+ );
80
+ }
81
+
82
+ internal static ProviderDiagnosticsView CreateProviderDiagnostics(
83
+ MessagingComponent component
84
+ )
85
+ {
86
+ bool autoConfigure = component.AutoConfigureSerializedProviderOnAwake;
87
+ bool hasSerializedProvider =
88
+ component.SerializedProviderAsset != null || component.HasSerializedProvider;
89
+ bool hasRuntimeProvider = component.HasRuntimeProvider;
90
+ bool hasMessageBusOverride = component.HasMessageBusOverride;
91
+ bool serializedProviderMissingWarning = autoConfigure && !hasSerializedProvider;
92
+
93
+ bool serializedProviderNullBusWarning = false;
94
+ if (hasSerializedProvider)
95
+ {
96
+ IMessageBus resolvedBus = component.SerializedProviderHandle.ResolveBus();
97
+ serializedProviderNullBusWarning = resolvedBus == null;
98
+ }
99
+
100
+ return new ProviderDiagnosticsView(
101
+ autoConfigure,
102
+ hasSerializedProvider,
103
+ hasRuntimeProvider,
104
+ hasMessageBusOverride,
105
+ serializedProviderMissingWarning,
106
+ serializedProviderNullBusWarning
107
+ );
108
+ }
109
+ }
110
+
111
+ internal sealed class MessagingComponentInspectorState
112
+ {
113
+ internal MessagingComponentInspectorState(
114
+ bool globalDiagnosticsEnabled,
115
+ IReadOnlyList<MessageEmissionData> globalEmissionHistory,
116
+ IReadOnlyList<ListenerDiagnosticsView> listeners,
117
+ ProviderDiagnosticsView providerDiagnostics
118
+ )
119
+ {
120
+ GlobalDiagnosticsEnabled = globalDiagnosticsEnabled;
121
+ GlobalEmissionHistory =
122
+ globalEmissionHistory
123
+ ?? throw new ArgumentNullException(nameof(globalEmissionHistory));
124
+ Listeners = listeners ?? throw new ArgumentNullException(nameof(listeners));
125
+ ProviderDiagnostics = providerDiagnostics;
126
+ }
127
+
128
+ internal bool GlobalDiagnosticsEnabled { get; }
129
+
130
+ internal IReadOnlyList<MessageEmissionData> GlobalEmissionHistory { get; }
131
+
132
+ internal IReadOnlyList<ListenerDiagnosticsView> Listeners { get; }
133
+
134
+ internal ProviderDiagnosticsView ProviderDiagnostics { get; }
135
+ }
136
+
137
+ internal sealed class ListenerDiagnosticsView
138
+ {
139
+ internal ListenerDiagnosticsView(
140
+ MonoBehaviour listener,
141
+ bool diagnosticsEnabled,
142
+ bool tokenEnabled,
143
+ IReadOnlyList<MessageRegistrationView> registrations,
144
+ IReadOnlyList<MessageEmissionData> emissionHistory
145
+ )
146
+ {
147
+ Listener = listener;
148
+ DiagnosticsEnabled = diagnosticsEnabled;
149
+ TokenEnabled = tokenEnabled;
150
+ Registrations = registrations ?? throw new ArgumentNullException(nameof(registrations));
151
+ EmissionHistory =
152
+ emissionHistory ?? throw new ArgumentNullException(nameof(emissionHistory));
153
+ }
154
+
155
+ internal MonoBehaviour Listener { get; }
156
+
157
+ internal bool DiagnosticsEnabled { get; }
158
+
159
+ internal bool TokenEnabled { get; }
160
+
161
+ internal IReadOnlyList<MessageRegistrationView> Registrations { get; }
162
+
163
+ internal IReadOnlyList<MessageEmissionData> EmissionHistory { get; }
164
+ }
165
+
166
+ internal readonly struct MessageRegistrationView
167
+ {
168
+ internal MessageRegistrationView(
169
+ MessageRegistrationHandle handle,
170
+ MessageRegistrationMetadata metadata,
171
+ int callCount
172
+ )
173
+ {
174
+ Handle = handle;
175
+ Metadata = metadata;
176
+ CallCount = callCount;
177
+ }
178
+
179
+ internal MessageRegistrationHandle Handle { get; }
180
+
181
+ internal MessageRegistrationMetadata Metadata { get; }
182
+
183
+ internal int CallCount { get; }
184
+ }
185
+
186
+ internal readonly struct ProviderDiagnosticsView
187
+ {
188
+ internal ProviderDiagnosticsView(
189
+ bool autoConfigureSerializedProviderOnAwake,
190
+ bool hasSerializedProvider,
191
+ bool hasRuntimeProvider,
192
+ bool hasMessageBusOverride,
193
+ bool serializedProviderMissingWarning,
194
+ bool serializedProviderNullBusWarning
195
+ )
196
+ {
197
+ AutoConfigureSerializedProviderOnAwake = autoConfigureSerializedProviderOnAwake;
198
+ HasSerializedProvider = hasSerializedProvider;
199
+ HasRuntimeProvider = hasRuntimeProvider;
200
+ HasMessageBusOverride = hasMessageBusOverride;
201
+ SerializedProviderMissingWarning = serializedProviderMissingWarning;
202
+ SerializedProviderNullBusWarning = serializedProviderNullBusWarning;
203
+ }
204
+
205
+ internal bool AutoConfigureSerializedProviderOnAwake { get; }
206
+
207
+ internal bool HasSerializedProvider { get; }
208
+
209
+ internal bool HasRuntimeProvider { get; }
210
+
211
+ internal bool HasMessageBusOverride { get; }
212
+
213
+ internal bool SerializedProviderMissingWarning { get; }
214
+
215
+ internal bool SerializedProviderNullBusWarning { get; }
216
+ }
217
+ }
218
+ #endif
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 2624c9e8eb5243ebb71545774f411c2c
3
+ timeCreated: 1761880591
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: a61780c8ba084b29bb44fdefc9b7fcf2
3
+ timeCreated: 1761880591
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Unity](https://img.shields.io/badge/Unity-2021.3+-black.svg)](https://unity.com/releases/editor)<br/>
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE.md)<br/>
5
- [![Version](https://img.shields.io/badge/version-2.0.0--rc27-green.svg)](package.json)<br/>
5
+ [![Version](https://img.shields.io/npm/v/com.wallstop-studios.dxmessaging.svg)](https://www.npmjs.com/package/com.wallstop-studios.dxmessaging)<br/>
6
6
  [![Performance: OS-Specific Benchmarks](https://img.shields.io/badge/Performance-OS--specific-blueviolet.svg)](Docs/Performance.md)<br/>
7
7
  [![Markdown Link Validity](https://github.com/wallstop/DxMessaging/actions/workflows/markdown-link-validity.yml/badge.svg)](https://github.com/wallstop/DxMessaging/actions/workflows/markdown-link-validity.yml)<br/>
8
8
  [![Markdown Link Text Check](https://github.com/wallstop/DxMessaging/actions/workflows/markdown-link-text-check.yml/badge.svg)](https://github.com/wallstop/DxMessaging/actions/workflows/markdown-link-text-check.yml)
@@ -11,6 +11,8 @@
11
11
 
12
12
  Think of it as **the event system Unity should have built-in** — one that actually scales.
13
13
 
14
+ Need install instructions for Git URLs, scoped registries, or tarballs? Jump to the [Install Guide](Docs/Install.md).
15
+
14
16
  ## Table of Contents
15
17
 
16
18
  - [30-Second Elevator Pitch](#30-second-elevator-pitch)
@@ -50,7 +52,7 @@ Think of it as **the event system Unity should have built-in** — one that actu
50
52
 
51
53
  1. **Untargeted** - "Everyone listen!" (pause game, settings changed)
52
54
  1. **Targeted** - "Tell Player to heal" (commands to specific entities)
53
- 1. **Broadcast** - "Enemy took damage" (events others can observe)
55
+ 1. **Broadcast** - "I took damage" (things that happen to _you_ that others can observe)
54
56
 
55
57
  **One line:** It's the event system Unity should have shipped with - type-safe, leak-proof, and actually debuggable. 🚀
56
58
 
@@ -62,12 +64,15 @@ Think of it as **the event system Unity should have built-in** — one that actu
62
64
 
63
65
  ### 1. Install
64
66
 
65
- Via Unity Package Manager → Add package from git URL:
67
+ Via Unity Package Manager → Add package from git URL (see the [Install Guide](Docs/Install.md) for scoped registry, tarball, and offline options):
66
68
 
67
- ```text
69
+ ```bash
70
+ # Unity Package Manager > Add package from git URL...
68
71
  https://github.com/wallstop/DxMessaging.git
69
72
  ```
70
73
 
74
+ Prefer OpenUPM, scoped registries, or local tarballs? The [Install Guide](Docs/Install.md) covers every path in detail.
75
+
71
76
  ### 2. Define Your First Message
72
77
 
73
78
  ```csharp
@@ -632,6 +637,7 @@ See [full comparison](Docs/Comparisons.md) for detailed analysis with code examp
632
637
 
633
638
  ### 📖 Reference
634
639
 
640
+ - [Install Guide](Docs/Install.md) — All install options (Git URL, scoped registry, tarball, manual copy)
635
641
  - [Glossary](Docs/Glossary.md) — All terms explained in plain English
636
642
  - [Quick Reference](Docs/QuickReference.md) — Cheat sheet
637
643
  - [API Reference](Docs/Reference.md) — Complete API
@@ -9,3 +9,4 @@ using System.Runtime.CompilerServices;
9
9
  [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.Reflex")]
10
10
  [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.VContainer")]
11
11
  [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.Zenject")]
12
+ [assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Editor")]
@@ -31,30 +31,82 @@ namespace DxMessaging.Core.Attributes
31
31
  /// Optional default value overloads. Values must be compile-time constants and
32
32
  /// will be validated by the source generator against the field type.
33
33
  /// </summary>
34
+ /// <summary>
35
+ /// Initializes the attribute with the specified default boolean value.
36
+ /// </summary>
37
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
34
38
  public DxOptionalParameterAttribute(bool value) { }
35
39
 
40
+ /// <summary>
41
+ /// Initializes the attribute with the specified default character value.
42
+ /// </summary>
43
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
36
44
  public DxOptionalParameterAttribute(char value) { }
37
45
 
46
+ /// <summary>
47
+ /// Initializes the attribute with the specified default string value.
48
+ /// </summary>
49
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
38
50
  public DxOptionalParameterAttribute(string value) { }
39
51
 
52
+ /// <summary>
53
+ /// Initializes the attribute with the specified default byte value.
54
+ /// </summary>
55
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
40
56
  public DxOptionalParameterAttribute(byte value) { }
41
57
 
58
+ /// <summary>
59
+ /// Initializes the attribute with the specified default signed byte value.
60
+ /// </summary>
61
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
42
62
  public DxOptionalParameterAttribute(sbyte value) { }
43
63
 
64
+ /// <summary>
65
+ /// Initializes the attribute with the specified default short value.
66
+ /// </summary>
67
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
44
68
  public DxOptionalParameterAttribute(short value) { }
45
69
 
70
+ /// <summary>
71
+ /// Initializes the attribute with the specified default unsigned short value.
72
+ /// </summary>
73
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
46
74
  public DxOptionalParameterAttribute(ushort value) { }
47
75
 
76
+ /// <summary>
77
+ /// Initializes the attribute with the specified default integer value.
78
+ /// </summary>
79
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
48
80
  public DxOptionalParameterAttribute(int value) { }
49
81
 
82
+ /// <summary>
83
+ /// Initializes the attribute with the specified default unsigned integer value.
84
+ /// </summary>
85
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
50
86
  public DxOptionalParameterAttribute(uint value) { }
51
87
 
88
+ /// <summary>
89
+ /// Initializes the attribute with the specified default long value.
90
+ /// </summary>
91
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
52
92
  public DxOptionalParameterAttribute(long value) { }
53
93
 
94
+ /// <summary>
95
+ /// Initializes the attribute with the specified default unsigned long value.
96
+ /// </summary>
97
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
54
98
  public DxOptionalParameterAttribute(ulong value) { }
55
99
 
100
+ /// <summary>
101
+ /// Initializes the attribute with the specified default single-precision floating point value.
102
+ /// </summary>
103
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
56
104
  public DxOptionalParameterAttribute(float value) { }
57
105
 
106
+ /// <summary>
107
+ /// Initializes the attribute with the specified default double-precision floating point value.
108
+ /// </summary>
109
+ /// <param name="value">Default value used when the constructor parameter is omitted.</param>
58
110
  public DxOptionalParameterAttribute(double value) { }
59
111
 
60
112
  /// <summary>
@@ -29,6 +29,10 @@ namespace DxMessaging.Core.DataStructure
29
29
  _current = default;
30
30
  }
31
31
 
32
+ /// <summary>
33
+ /// Advances the enumerator to the next element in chronological order.
34
+ /// </summary>
35
+ /// <returns><c>true</c> when another element is available; otherwise <c>false</c>.</returns>
32
36
  public bool MoveNext()
33
37
  {
34
38
  if (++_index < _buffer.Count)
@@ -41,16 +45,25 @@ namespace DxMessaging.Core.DataStructure
41
45
  return false;
42
46
  }
43
47
 
48
+ /// <summary>
49
+ /// Gets the element at the current enumerator position.
50
+ /// </summary>
44
51
  public T Current => _current;
45
52
 
46
53
  object IEnumerator.Current => Current;
47
54
 
55
+ /// <summary>
56
+ /// Resets the enumerator to its initial position before the first element.
57
+ /// </summary>
48
58
  public void Reset()
49
59
  {
50
60
  _index = -1;
51
61
  _current = default;
52
62
  }
53
63
 
64
+ /// <summary>
65
+ /// Releases resources held by the enumerator.
66
+ /// </summary>
54
67
  public void Dispose() { }
55
68
  }
56
69
 
@@ -107,6 +120,9 @@ namespace DxMessaging.Core.DataStructure
107
120
  }
108
121
  }
109
122
 
123
+ /// <summary>
124
+ /// Creates an enumerator that iterates from the oldest element to the most recently added.
125
+ /// </summary>
110
126
  public CyclicBufferEnumerator GetEnumerator()
111
127
  {
112
128
  return new CyclicBufferEnumerator(this);
@@ -1,15 +1,18 @@
1
1
  namespace DxMessaging.Core.Diagnostics
2
2
  {
3
3
  using System;
4
- #if UNITY_2017_1_OR_NEWER
4
+ using System.Linq;
5
+ #if UNITY_2021_3_OR_NEWER
5
6
  using UnityEngine;
7
+ #else
8
+ using System.Diagnostics;
6
9
  #endif
7
10
 
8
11
  /// <summary>
9
12
  /// Captures a snapshot of a message emission for diagnostics.
10
13
  /// </summary>
11
14
  /// <remarks>
12
- /// When diagnostics are enabled (see <see cref="MessageBus.IMessageBus.GlobalDiagnosticsMode"/>),
15
+ /// When diagnostics are enabled (see <see cref="MessageBus.IMessageBus.GlobalDiagnosticsTargets"/>),
13
16
  /// the bus and tokens record recent emissions in ring buffers along with a trimmed stack trace
14
17
  /// that excludes DxMessaging internals for easier debugging.
15
18
  ///
@@ -45,7 +48,7 @@ namespace DxMessaging.Core.Diagnostics
45
48
  private static string GetAccurateStackTrace()
46
49
  {
47
50
  string fullStackTrace;
48
- #if UNITY_2017_1_OR_NEWER
51
+ #if UNITY_2021_3_OR_NEWER
49
52
  fullStackTrace = StackTraceUtility.ExtractStackTrace();
50
53
  #else
51
54
  fullStackTrace = new StackTrace(true).ToString();
@@ -57,18 +60,30 @@ namespace DxMessaging.Core.Diagnostics
57
60
 
58
61
  string[] lines = fullStackTrace.Split(NewlineSeparators, StringSplitOptions.None);
59
62
 
60
- int startIndex = 1;
61
- while (
62
- startIndex < lines.Length
63
- && lines[startIndex].Contains("DxMessaging", StringComparison.OrdinalIgnoreCase)
64
- )
63
+ string[] trimmedLines = lines
64
+ .Where(line => !string.IsNullOrWhiteSpace(line) && !IsInternalFrame(line))
65
+ .ToArray();
66
+
67
+ return trimmedLines.Length == 0
68
+ ? string.Empty
69
+ : string.Join(JoinSeparator, trimmedLines);
70
+ }
71
+
72
+ private static bool IsInternalFrame(string line)
73
+ {
74
+ if (string.IsNullOrWhiteSpace(line))
65
75
  {
66
- ++startIndex;
76
+ return false;
67
77
  }
68
78
 
69
- return lines.Length <= startIndex
70
- ? string.Empty
71
- : string.Join(JoinSeparator, lines, startIndex, lines.Length - startIndex);
79
+ if (!line.Contains("DxMessaging.", StringComparison.Ordinal))
80
+ {
81
+ return false;
82
+ }
83
+
84
+ return line.Contains("DxMessaging.Core.", StringComparison.Ordinal)
85
+ || line.Contains("DxMessaging.Unity.", StringComparison.Ordinal)
86
+ || line.Contains("DxMessaging.Editor.", StringComparison.Ordinal);
72
87
  }
73
88
  }
74
89
  }
@@ -1,21 +1,83 @@
1
1
  namespace DxMessaging.Core.Diagnostics
2
2
  {
3
+ /// <summary>
4
+ /// Categories used when recording registrations in diagnostics logs.
5
+ /// </summary>
3
6
  public enum MessageRegistrationType
4
7
  {
8
+ /// <summary>
9
+ /// No registration type was captured.
10
+ /// </summary>
5
11
  None = 0,
12
+
13
+ /// <summary>
14
+ /// A targeted handler that listens for messages addressed to a specific <see cref="Core.InstanceId"/>.
15
+ /// </summary>
6
16
  Targeted = 1,
17
+
18
+ /// <summary>
19
+ /// A global untargeted handler that receives all messages of a given type.
20
+ /// </summary>
7
21
  Untargeted = 2,
22
+
23
+ /// <summary>
24
+ /// A broadcast handler that listens for messages emitted from a source <see cref="Core.InstanceId"/>.
25
+ /// </summary>
8
26
  Broadcast = 3,
27
+
28
+ /// <summary>
29
+ /// A broadcast post-processor that runs after broadcast handlers complete.
30
+ /// </summary>
9
31
  BroadcastPostProcessor = 4,
32
+
33
+ /// <summary>
34
+ /// A targeted post-processor that runs after targeted handlers complete.
35
+ /// </summary>
10
36
  TargetedPostProcessor = 5,
37
+
38
+ /// <summary>
39
+ /// A targeted handler that ignores the concrete target during invocation.
40
+ /// </summary>
11
41
  TargetedWithoutTargeting = 6,
42
+
43
+ /// <summary>
44
+ /// A post-processor for handlers registered without a concrete target.
45
+ /// </summary>
12
46
  TargetedWithoutTargetingPostProcessor = 7,
47
+
48
+ /// <summary>
49
+ /// A broadcast handler registered without an explicit source identity.
50
+ /// </summary>
13
51
  BroadcastWithoutSource = 8,
52
+
53
+ /// <summary>
54
+ /// A post-processor for broadcast handlers registered without an explicit source.
55
+ /// </summary>
14
56
  BroadcastWithoutSourcePostProcessor = 9,
57
+
58
+ /// <summary>
59
+ /// A post-processor that runs after untargeted handlers complete.
60
+ /// </summary>
15
61
  UntargetedPostProcessor = 10,
62
+
63
+ /// <summary>
64
+ /// A global catch-all registration that observes every message.
65
+ /// </summary>
16
66
  GlobalAcceptAll = 11,
67
+
68
+ /// <summary>
69
+ /// An untargeted interceptor that can mutate or cancel global messages.
70
+ /// </summary>
17
71
  UntargetedInterceptor = 12,
72
+
73
+ /// <summary>
74
+ /// A targeted interceptor that can mutate or cancel messages bound to a specific recipient.
75
+ /// </summary>
18
76
  TargetedInterceptor = 13,
77
+
78
+ /// <summary>
79
+ /// A broadcast interceptor that can mutate or cancel messages emitted from a source.
80
+ /// </summary>
19
81
  BroadcastInterceptor = 14,
20
82
  }
21
83
  }
@@ -0,0 +1,108 @@
1
+ namespace DxMessaging.Core
2
+ {
3
+ using System;
4
+ using Helper;
5
+ using MessageBus;
6
+
7
+ /// <summary>
8
+ /// Centralised utility for resetting DxMessaging static state when Domain Reload is disabled.
9
+ /// </summary>
10
+ public static class DxMessagingStaticState
11
+ {
12
+ private static readonly object ResetLock = new object();
13
+ private static readonly BaselineState Baseline;
14
+
15
+ static DxMessagingStaticState()
16
+ {
17
+ Baseline = CaptureBaseline();
18
+ }
19
+
20
+ /// <summary>
21
+ /// Resets all static variables in DxMessaging to their default values.
22
+ /// </summary>
23
+ public static void Reset()
24
+ {
25
+ lock (ResetLock)
26
+ {
27
+ MessagingDebug.enabled = Baseline.MessagingDebugEnabled;
28
+ MessagingDebug.LogFunction = Baseline.MessagingDebugLogFunction;
29
+
30
+ IMessageBus.GlobalDiagnosticsTargets = Baseline.GlobalDiagnosticsTargets;
31
+ IMessageBus.GlobalMessageBufferSize = Baseline.GlobalMessageBufferSize;
32
+ IMessageBus.GlobalSequentialIndex = Baseline.GlobalSequentialIndex;
33
+
34
+ MessageHelperIndexer.RestoreState(Baseline.HelperState);
35
+
36
+ MessageRegistrationHandle.SetIdSeed(Baseline.MessageRegistrationHandleSeed);
37
+ MessageRegistrationBuilder.SetSyntheticOwnerCounter(Baseline.SyntheticOwnerCounter);
38
+
39
+ MessageHandler.ResetStatics();
40
+ IMessageBus.GlobalSequentialIndex = Baseline.GlobalSequentialIndex;
41
+ }
42
+ }
43
+
44
+ private static BaselineState CaptureBaseline()
45
+ {
46
+ bool messagingDebugEnabled = MessagingDebug.enabled;
47
+ Action<LogLevel, string> messagingDebugLogFunction = MessagingDebug.LogFunction;
48
+ DiagnosticsTarget globalDiagnosticsTargets = IMessageBus.GlobalDiagnosticsTargets;
49
+ int globalMessageBufferSize = IMessageBus.GlobalMessageBufferSize;
50
+ int globalSequentialIndex = IMessageBus.GlobalSequentialIndex;
51
+ long messageRegistrationHandleSeed = MessageRegistrationHandle.GetCurrentIdSeed();
52
+ int syntheticOwnerCounter = MessageRegistrationBuilder.GetSyntheticOwnerCounter();
53
+ MessageHelperIndexer.MessageHelperIndexerState helperState =
54
+ MessageHelperIndexer.CaptureState();
55
+
56
+ return new BaselineState(
57
+ messagingDebugEnabled,
58
+ messagingDebugLogFunction,
59
+ globalDiagnosticsTargets,
60
+ globalMessageBufferSize,
61
+ globalSequentialIndex,
62
+ messageRegistrationHandleSeed,
63
+ syntheticOwnerCounter,
64
+ helperState
65
+ );
66
+ }
67
+
68
+ private sealed class BaselineState
69
+ {
70
+ internal BaselineState(
71
+ bool messagingDebugEnabled,
72
+ Action<LogLevel, string> messagingDebugLogFunction,
73
+ DiagnosticsTarget globalDiagnosticsTargets,
74
+ int globalMessageBufferSize,
75
+ int globalSequentialIndex,
76
+ long messageRegistrationHandleSeed,
77
+ int syntheticOwnerCounter,
78
+ MessageHelperIndexer.MessageHelperIndexerState helperState
79
+ )
80
+ {
81
+ MessagingDebugEnabled = messagingDebugEnabled;
82
+ MessagingDebugLogFunction = messagingDebugLogFunction;
83
+ GlobalDiagnosticsTargets = globalDiagnosticsTargets;
84
+ GlobalMessageBufferSize = globalMessageBufferSize;
85
+ GlobalSequentialIndex = globalSequentialIndex;
86
+ MessageRegistrationHandleSeed = messageRegistrationHandleSeed;
87
+ SyntheticOwnerCounter = syntheticOwnerCounter;
88
+ HelperState = helperState;
89
+ }
90
+
91
+ internal bool MessagingDebugEnabled { get; }
92
+
93
+ internal Action<LogLevel, string> MessagingDebugLogFunction { get; }
94
+
95
+ internal DiagnosticsTarget GlobalDiagnosticsTargets { get; }
96
+
97
+ internal int GlobalMessageBufferSize { get; }
98
+
99
+ internal int GlobalSequentialIndex { get; }
100
+
101
+ internal long MessageRegistrationHandleSeed { get; }
102
+
103
+ internal int SyntheticOwnerCounter { get; }
104
+
105
+ internal MessageHelperIndexer.MessageHelperIndexerState HelperState { get; }
106
+ }
107
+ }
108
+ }