com.wallstop-studios.dxmessaging 2.0.0-rc27.3.1 β 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/format-on-demand.yml +2 -2
- package/.github/workflows/json-format-check.yml +1 -1
- package/.github/workflows/markdown-json.yml +1 -1
- package/.github/workflows/markdownlint.yml +1 -1
- package/.github/workflows/npm-publish.yml +1 -1
- package/.github/workflows/prettier-autofix.yml +2 -2
- package/.github/workflows/yaml-format-lint.yml +1 -1
- package/Docs/Advanced.md +26 -1
- package/Docs/Comparisons.md +1352 -141
- package/Docs/Compatibility.md +27 -0
- package/Docs/DesignAndArchitecture.md +41 -34
- package/Docs/EmitShorthands.md +34 -0
- package/Docs/GettingStarted.md +84 -17
- package/Docs/Helpers.md +1 -1
- package/Docs/Index.md +28 -25
- package/Docs/Install.md +29 -6
- package/Docs/Integrations/Reflex.md +292 -0
- package/Docs/Integrations/Reflex.md.meta +7 -0
- package/Docs/Integrations/VContainer.md +324 -0
- package/Docs/Integrations/VContainer.md.meta +7 -0
- package/Docs/Integrations/Zenject.md +333 -0
- package/Docs/Integrations/Zenject.md.meta +7 -0
- package/{Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.pdb.meta β Docs/Integrations.meta} +2 -1
- package/Docs/InterceptorsAndOrdering.md +371 -17
- package/Docs/ListeningPatterns.md +206 -0
- package/Docs/MessageBusProviders.md +496 -0
- package/Docs/MessageBusProviders.md.meta +7 -0
- package/Docs/MessageTypes.md +27 -0
- package/Docs/MigrationGuide.md +45 -0
- package/Docs/Overview.md +114 -20
- package/Docs/Patterns.md +327 -2
- package/Docs/Performance.md +9 -9
- package/Docs/QuickReference.md +31 -0
- package/Docs/RuntimeConfiguration.md +407 -0
- package/Docs/RuntimeConfiguration.md.meta +7 -0
- package/Docs/UnityIntegration.md +3 -1
- package/Docs/VisualGuide.md +281 -167
- package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll +0 -0
- package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +3 -3
- package/Editor/Analyzers/Microsoft.CodeAnalysis.dll +0 -0
- package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +2 -2
- package/Editor/Analyzers/System.Collections.Immutable.dll +0 -0
- package/Editor/Analyzers/System.Reflection.Metadata.dll +0 -0
- package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
- package/Editor/CustomEditors/MessagingComponentEditor.cs +15 -6
- package/README.md +388 -67
- package/Runtime/AssemblyInfo.cs +4 -0
- package/Runtime/Core/Extensions/MessageBusExtensions.cs +253 -0
- package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -0
- package/Runtime/Core/Extensions/MessageExtensions.cs +137 -89
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs +23 -0
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -0
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs +14 -0
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +18 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs +26 -0
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +383 -0
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -0
- package/Runtime/Core/MessageHandler.cs +198 -27
- package/Runtime/Core/MessageRegistrationToken.cs +67 -25
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs +31 -0
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +12 -0
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs +38 -0
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +12 -0
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +73 -0
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +11 -0
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef +20 -0
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/Reflex.meta +8 -0
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +46 -0
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +11 -0
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef +30 -0
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/VContainer.meta +8 -0
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef +30 -0
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +55 -0
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +11 -0
- package/Runtime/Unity/Integrations/Zenject.meta +8 -0
- package/Runtime/Unity/Integrations.meta +8 -0
- package/Runtime/Unity/MessageAwareComponent.cs +102 -0
- package/Runtime/Unity/MessageBusProviderHandle.cs +97 -0
- package/Runtime/Unity/MessageBusProviderHandle.cs.meta +12 -0
- package/Runtime/Unity/MessagingComponent.cs +164 -2
- package/Runtime/Unity/MessagingComponentInstaller.cs +120 -0
- package/Runtime/Unity/MessagingComponentInstaller.cs.meta +12 -0
- package/Runtime/Unity/ScriptableMessageBusProvider.cs +14 -0
- package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +12 -0
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab +98 -0
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab.meta +7 -0
- package/Samples~/DI/Prefabs.meta +8 -0
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset +14 -0
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset.meta +8 -0
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset +14 -0
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset.meta +8 -0
- package/Samples~/DI/Providers.meta +8 -0
- package/Samples~/DI/README.md +51 -0
- package/Samples~/DI/README.md.meta +7 -0
- package/Samples~/DI/Reflex/SampleInstaller.cs +75 -0
- package/Samples~/DI/Reflex/SampleInstaller.cs.meta +11 -0
- package/Samples~/DI/Reflex.meta +8 -0
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs +81 -0
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -0
- package/Samples~/DI/VContainer.meta +8 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs +67 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs.meta +11 -0
- package/Samples~/DI/Zenject.meta +8 -0
- package/Samples~/DI.meta +8 -0
- package/Samples~/Mini Combat/README.md +86 -28
- package/Samples~/Mini Combat/Walkthrough.md +41 -25
- package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs +12 -2
- package/Samples~/UI Buttons + Inspector/README.md +55 -12
- package/Samples~/UI Buttons + Inspector/README.md.meta +7 -0
- package/Tests/Runtime/Benchmarks/BenchmarkSession.cs +444 -0
- package/Tests/Runtime/Benchmarks/BenchmarkSession.cs.meta +11 -0
- package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs +94 -0
- package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs.meta +11 -0
- package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs +395 -0
- package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs.meta +11 -0
- package/Tests/Runtime/Benchmarks/PerformanceTests.cs +77 -429
- package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs +142 -0
- package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs.meta +12 -0
- package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef +50 -0
- package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef.meta +7 -0
- package/Tests/Runtime/Core/DefaultBusFallbackTests.cs +333 -0
- package/Tests/Runtime/Core/DefaultBusFallbackTests.cs.meta +11 -0
- package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs +278 -0
- package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs.meta +11 -0
- package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs +289 -0
- package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs.meta +11 -0
- package/Tests/Runtime/Core/Extensions.meta +8 -0
- package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs +57 -0
- package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs.meta +11 -0
- package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs +219 -0
- package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs.meta +11 -0
- package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs +204 -0
- package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs.meta +11 -0
- package/Tests/Runtime/Core/MessagingTestBase.cs +4 -4
- package/Tests/Runtime/Core/NominalTests.cs +2 -2
- package/Tests/Runtime/Core/SourceGeneratorNestedTests.cs +1 -1
- package/Tests/Runtime/Core/TypedShorthandTests.cs +2 -2
- package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs +1 -1
- package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +2 -4
- package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs +162 -0
- package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset +16 -0
- package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset.meta +8 -0
- package/Tests/Runtime/Integrations/Reflex/Resources.meta +8 -0
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef +27 -0
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef.meta +7 -0
- package/Tests/Runtime/Integrations/Reflex.meta +8 -0
- package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs +140 -0
- package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef +37 -0
- package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef.meta +7 -0
- package/Tests/Runtime/Integrations/VContainer.meta +8 -0
- package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef +37 -0
- package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef.meta +7 -0
- package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs +140 -0
- package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/Zenject.meta +8 -0
- package/Tests/Runtime/Integrations.meta +8 -0
- package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs +1 -1
- package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +1 -1
- package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs +1 -1
- package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs +64 -0
- package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs.meta +12 -0
- package/Tests/Runtime/TestUtilities.meta +9 -0
- package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs +57 -0
- package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs.meta +11 -0
- package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs +107 -0
- package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs.meta +12 -0
- package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs +210 -0
- package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs.meta +12 -0
- package/Tests/Runtime/Unity.meta +9 -0
- package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef +3 -1
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@ namespace DxMessaging.Editor.CustomEditors
|
|
|
5
5
|
using System.Linq;
|
|
6
6
|
using Core;
|
|
7
7
|
using Core.Diagnostics;
|
|
8
|
+
using Core.MessageBus;
|
|
8
9
|
using Core.Messages;
|
|
9
10
|
using Unity;
|
|
10
11
|
using UnityEditor;
|
|
@@ -107,18 +108,26 @@ namespace DxMessaging.Editor.CustomEditors
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
IMessageBus globalBus = MessageHandler.MessageBus;
|
|
112
|
+
if (globalBus is not MessageBus concreteBus)
|
|
113
|
+
{
|
|
114
|
+
EditorGUILayout.HelpBox(
|
|
115
|
+
"Global diagnostics controls are unavailable because the active global bus is not the default DxMessaging MessageBus implementation.",
|
|
116
|
+
MessageType.Info
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
else if (!concreteBus.DiagnosticsMode)
|
|
111
120
|
{
|
|
112
121
|
if (GUILayout.Button("Enable Global Diagnostics"))
|
|
113
122
|
{
|
|
114
|
-
|
|
123
|
+
concreteBus.DiagnosticsMode = true;
|
|
115
124
|
}
|
|
116
125
|
}
|
|
117
126
|
else
|
|
118
127
|
{
|
|
119
128
|
if (GUILayout.Button("Disable Global Diagnostics"))
|
|
120
129
|
{
|
|
121
|
-
|
|
130
|
+
concreteBus.DiagnosticsMode = false;
|
|
122
131
|
}
|
|
123
132
|
else
|
|
124
133
|
{
|
|
@@ -130,7 +139,7 @@ namespace DxMessaging.Editor.CustomEditors
|
|
|
130
139
|
"Global Messages",
|
|
131
140
|
true
|
|
132
141
|
);
|
|
133
|
-
int totalGlobalMessages =
|
|
142
|
+
int totalGlobalMessages = concreteBus._emissionBuffer.Count;
|
|
134
143
|
if (_globalBufferExpanded && totalGlobalMessages > 0)
|
|
135
144
|
{
|
|
136
145
|
int page = _globalBufferPaging;
|
|
@@ -163,8 +172,8 @@ namespace DxMessaging.Editor.CustomEditors
|
|
|
163
172
|
}
|
|
164
173
|
}
|
|
165
174
|
|
|
166
|
-
MessageEmissionData[] pagedGlobalMessages =
|
|
167
|
-
.
|
|
175
|
+
MessageEmissionData[] pagedGlobalMessages = concreteBus
|
|
176
|
+
._emissionBuffer.Reverse()
|
|
168
177
|
.Skip(page * PageSize)
|
|
169
178
|
.Take(PageSize)
|
|
170
179
|
.ToArray();
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DxMessaging for Unity β The Modern Event System
|
|
2
2
|
|
|
3
|
-
[](https://unity.com/
|
|
3
|
+
[](https://unity.com/releases/editor)<br/>
|
|
4
4
|
[](LICENSE.md)<br/>
|
|
5
5
|
[](package.json)<br/>
|
|
6
6
|
[](Docs/Performance.md)<br/>
|
|
@@ -32,17 +32,27 @@ Think of it as **the event system Unity should have built-in** β one that actu
|
|
|
32
32
|
|
|
33
33
|
## 30-Second Elevator Pitch
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
### If you've ever
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
- Forgotten to unsubscribe from an event and spent hours debugging memory leaks
|
|
38
|
+
- Had UI code tangled with 15 different game systems
|
|
39
|
+
- Wondered "which event fired when?" with no way to see message flow
|
|
40
|
+
- Copy-pasted event boilerplate dozens of times
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
1. **Targeted** - "Hey YOU!" (commands to specific objects)
|
|
41
|
-
1. **Broadcast** - "I did something!" (events from sources)
|
|
42
|
+
#### Then DxMessaging solves your problems
|
|
42
43
|
|
|
43
|
-
**
|
|
44
|
+
- **Zero memory leaks** - automatic lifecycle management, no manual unsubscribe
|
|
45
|
+
- **Zero coupling** - systems communicate without knowing each other exist
|
|
46
|
+
- **Full visibility** - see every message in the Inspector with timestamps and payloads
|
|
47
|
+
- **Complete control** - priority-based ordering, validation, and interception
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
##### Three simple message types
|
|
50
|
+
|
|
51
|
+
1. **Untargeted** - "Everyone listen!" (pause game, settings changed)
|
|
52
|
+
1. **Targeted** - "Tell Player to heal" (commands to specific entities)
|
|
53
|
+
1. **Broadcast** - "Enemy took damage" (events others can observe)
|
|
54
|
+
|
|
55
|
+
**One line:** It's the event system Unity should have shipped with - type-safe, leak-proof, and actually debuggable. π
|
|
46
56
|
|
|
47
57
|
---
|
|
48
58
|
|
|
@@ -103,6 +113,57 @@ msg.EmitComponentTargeted(chestComponent);
|
|
|
103
113
|
|
|
104
114
|
---
|
|
105
115
|
|
|
116
|
+
## π§ Dependency Injection (DI) Compatible
|
|
117
|
+
|
|
118
|
+
**Using Zenject, VContainer, or Reflex?** DxMessaging is fully DI-compatible out of the box!
|
|
119
|
+
|
|
120
|
+
```csharp
|
|
121
|
+
// Inject IMessageBus in any class
|
|
122
|
+
public class PlayerService : IInitializable, IDisposable
|
|
123
|
+
{
|
|
124
|
+
private readonly MessageRegistrationLease _lease;
|
|
125
|
+
|
|
126
|
+
public PlayerService(IMessageRegistrationBuilder builder)
|
|
127
|
+
{
|
|
128
|
+
// Builder automatically resolves your container-managed bus
|
|
129
|
+
_lease = builder.Build(new MessageRegistrationBuildOptions
|
|
130
|
+
{
|
|
131
|
+
Configure = token => token.RegisterUntargeted<PlayerSpawned>(OnSpawn)
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public void Initialize() => _lease.Activate();
|
|
136
|
+
public void Dispose() => _lease.Dispose();
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Why use DI + Messaging?
|
|
141
|
+
|
|
142
|
+
- **DI for construction** β Inject services, repositories, managers via constructors
|
|
143
|
+
- **Messaging for events** β Reactive, decoupled communication for gameplay events
|
|
144
|
+
- **Best of both worlds** β Clean architecture with testable, isolated buses
|
|
145
|
+
|
|
146
|
+
#### Automatic integration for
|
|
147
|
+
|
|
148
|
+
- β
**Zenject/Extenject** β Full-featured DI with extensive Unity support
|
|
149
|
+
- β
**VContainer** β Lightweight, high-performance DI with scoped lifetimes
|
|
150
|
+
- β
**Reflex** β Minimal API, blazing-fast dependency injection
|
|
151
|
+
|
|
152
|
+
##### Get started
|
|
153
|
+
|
|
154
|
+
- [Zenject Integration Guide](Docs/Integrations/Zenject.md) β Complete setup with examples
|
|
155
|
+
- [VContainer Integration Guide](Docs/Integrations/VContainer.md) β Scoped buses for scene isolation
|
|
156
|
+
- [Reflex Integration Guide](Docs/Integrations/Reflex.md) β Minimal, lightweight patterns
|
|
157
|
+
|
|
158
|
+
##### Core DI concepts
|
|
159
|
+
|
|
160
|
+
- [Runtime Configuration](Docs/RuntimeConfiguration.md) β Setting message buses at runtime, re-binding registrations
|
|
161
|
+
- [Message Bus Providers](Docs/MessageBusProviders.md) β Provider system for design-time and runtime bus configuration
|
|
162
|
+
|
|
163
|
+
**Not using DI?** No problem! DxMessaging works perfectly standalone with zero dependencies.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
106
167
|
## Is DxMessaging Right for You
|
|
107
168
|
|
|
108
169
|
### β
Use DxMessaging When
|
|
@@ -113,6 +174,7 @@ msg.EmitComponentTargeted(chestComponent);
|
|
|
113
174
|
- **You value observability** - Need to debug "what fired when?" or track message flow
|
|
114
175
|
- **Teams/long-term maintenance** - Multiple developers, or you'll maintain this code for years
|
|
115
176
|
- **You want decoupling** - Hate when UI classes need references to 15 different game systems
|
|
177
|
+
- **You're using DI frameworks** - Seamless integration with Zenject/VContainer/Reflex (see [DI Compatible](#-dependency-injection-di-compatible))
|
|
116
178
|
|
|
117
179
|
### β Don't Use DxMessaging When
|
|
118
180
|
|
|
@@ -152,95 +214,194 @@ Looking for hard numbers? See OS-specific [Performance Benchmarks](Docs/Performa
|
|
|
152
214
|
|
|
153
215
|
## Why DxMessaging
|
|
154
216
|
|
|
155
|
-
### The
|
|
217
|
+
### The Problems You've Probably Hit
|
|
218
|
+
|
|
219
|
+
#### Scenario 1: The Memory Leak Nightmare
|
|
220
|
+
|
|
221
|
+
You write this innocent-looking code:
|
|
222
|
+
|
|
223
|
+
```csharp
|
|
224
|
+
public class GameUI : MonoBehaviour {
|
|
225
|
+
void OnEnable() {
|
|
226
|
+
GameManager.Instance.OnScoreChanged += UpdateScore;
|
|
227
|
+
}
|
|
228
|
+
// Oops, forgot OnDisable... leak! π
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Months later: "Why is our game using 2GB of RAM after an hour?"
|
|
233
|
+
|
|
234
|
+
##### Scenario 2: The Spaghetti Mess
|
|
156
235
|
|
|
157
236
|
```csharp
|
|
158
|
-
// C# Events: Manual lifecycle hell
|
|
159
237
|
public class GameUI : MonoBehaviour {
|
|
160
238
|
[SerializeField] private Player player;
|
|
161
239
|
[SerializeField] private EnemySpawner spawner;
|
|
240
|
+
[SerializeField] private InventorySystem inventory;
|
|
241
|
+
[SerializeField] private QuestSystem quests;
|
|
242
|
+
[SerializeField] private AudioManager audio;
|
|
243
|
+
// ... 15 more SerializeFields ...
|
|
162
244
|
|
|
163
245
|
void Awake() {
|
|
164
246
|
player.OnHealthChanged += UpdateHealth;
|
|
165
247
|
spawner.OnWaveStart += ShowWave;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
// Easy to forget = memory leaks
|
|
170
|
-
player.OnHealthChanged -= UpdateHealth;
|
|
171
|
-
spawner.OnWaveStart -= ShowWave;
|
|
248
|
+
inventory.OnItemAdded += RefreshInventory;
|
|
249
|
+
quests.OnQuestCompleted += ShowQuestNotification;
|
|
250
|
+
// ... 20 more subscriptions ...
|
|
172
251
|
}
|
|
173
252
|
}
|
|
174
253
|
```
|
|
175
254
|
|
|
176
|
-
|
|
255
|
+
**Your UI now depends on EVERYTHING.** Good luck refactoring that.
|
|
256
|
+
|
|
257
|
+
###### Scenario 3: The Debugging Black Hole
|
|
258
|
+
|
|
259
|
+
Player reports: "My health bar didn't update!"
|
|
260
|
+
|
|
261
|
+
You think: "Okay, which of the 47 events touching health failed? And in what order?"
|
|
177
262
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
263
|
+
**30 minutes later:** Still setting breakpoints everywhere...
|
|
264
|
+
|
|
265
|
+
### Common Problems
|
|
266
|
+
|
|
267
|
+
- β **Memory leaks** from forgotten unsubscribes (every Unity dev's nightmare)
|
|
268
|
+
- β **Tight coupling** making refactoring terrifying ("change one thing, break five others")
|
|
269
|
+
- β **No execution order control** ("why does the UI update before the player takes damage?")
|
|
270
|
+
- β **Impossible to debug** ("what fired when?" has no answer)
|
|
271
|
+
- β **Boilerplate overload** (write 50 lines for 3 events)
|
|
182
272
|
|
|
183
273
|
### The DxMessaging Solution
|
|
184
274
|
|
|
275
|
+
#### Same scenarios, zero pain
|
|
276
|
+
|
|
277
|
+
##### Scenario 1: No More Memory Leaks
|
|
278
|
+
|
|
185
279
|
```csharp
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
280
|
+
public class GameUI : MessageAwareComponent {
|
|
281
|
+
protected override void RegisterMessageHandlers() {
|
|
282
|
+
base.RegisterMessageHandlers();
|
|
283
|
+
_ = Token.RegisterUntargeted<ScoreChanged>(UpdateScore);
|
|
284
|
+
}
|
|
285
|
+
// That's it! No manual cleanup needed.
|
|
286
|
+
// Token automatically handles OnEnable/OnDisable/OnDestroy
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Automatic lifecycle = impossible to leak.** π
|
|
291
|
+
|
|
292
|
+
###### Scenario 2: No More Coupling
|
|
293
|
+
|
|
294
|
+
```csharp
|
|
295
|
+
public class GameUI : MessageAwareComponent {
|
|
296
|
+
// Zero SerializeFields! Zero references!
|
|
297
|
+
|
|
298
|
+
protected override void RegisterMessageHandlers() {
|
|
299
|
+
base.RegisterMessageHandlers();
|
|
300
|
+
_ = Token.RegisterUntargeted<HealthChanged>(OnHealth);
|
|
301
|
+
_ = Token.RegisterUntargeted<WaveStarted>(OnWave);
|
|
302
|
+
_ = Token.RegisterUntargeted<ItemAdded>(OnItem);
|
|
303
|
+
// Listen to anything, from anywhere, no coupling
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Your UI is now independent.** Swap systems freely without breaking anything.
|
|
309
|
+
|
|
310
|
+
###### Scenario 3: Debugging is Built In
|
|
311
|
+
|
|
312
|
+
Open any `MessageAwareComponent` in the Inspector:
|
|
313
|
+
|
|
314
|
+
```text
|
|
315
|
+
Message History (last 50):
|
|
316
|
+
[12:34:56] HealthChanged (amount: 25) β Priority: 0
|
|
317
|
+
[12:34:55] ItemAdded (id: 42, count: 1) β Priority: 5
|
|
318
|
+
[12:34:54] WaveStarted (wave: 3) β Priority: 0
|
|
319
|
+
|
|
320
|
+
Active Registrations:
|
|
321
|
+
β HealthChanged (5 handlers)
|
|
322
|
+
β ItemAdded (2 handlers)
|
|
323
|
+
```
|
|
189
324
|
|
|
190
|
-
|
|
325
|
+
**See exactly what fired, when, and who handled it.** No guesswork.
|
|
326
|
+
|
|
327
|
+
### How It Transforms Your Code
|
|
328
|
+
|
|
329
|
+
```csharp
|
|
330
|
+
// 1. Define messages (clean, typed, discoverable)
|
|
191
331
|
[DxTargetedMessage]
|
|
192
332
|
[DxAutoConstructor]
|
|
193
333
|
public readonly partial struct Heal { public readonly int amount; }
|
|
194
334
|
|
|
195
335
|
// 2. Listen (automatic lifecycle - zero leaks)
|
|
196
|
-
public class
|
|
336
|
+
public class Player : MessageAwareComponent {
|
|
197
337
|
protected override void RegisterMessageHandlers() {
|
|
198
338
|
base.RegisterMessageHandlers();
|
|
199
339
|
_ = Token.RegisterComponentTargeted<Heal>(this, OnHeal);
|
|
200
340
|
}
|
|
201
341
|
|
|
202
|
-
void OnHeal(ref Heal m)
|
|
342
|
+
void OnHeal(ref Heal m) {
|
|
343
|
+
health += m.amount;
|
|
344
|
+
Debug.Log($"Healed {m.amount}!");
|
|
345
|
+
}
|
|
203
346
|
}
|
|
204
347
|
|
|
205
|
-
// 3. Send (
|
|
206
|
-
var heal = new Heal(
|
|
207
|
-
heal.
|
|
348
|
+
// 3. Send (from anywhere - zero coupling)
|
|
349
|
+
var heal = new Heal(50);
|
|
350
|
+
heal.EmitComponentTargeted(playerComponent);
|
|
208
351
|
```
|
|
209
352
|
|
|
210
|
-
|
|
353
|
+
#### What you get
|
|
211
354
|
|
|
212
|
-
- β
**Zero memory leaks** -
|
|
213
|
-
- β
**
|
|
214
|
-
- β
**
|
|
215
|
-
- β
**
|
|
216
|
-
- β
**
|
|
217
|
-
- β
**Intercept & validate** - enforce rules before handlers run
|
|
355
|
+
- β
**Zero memory leaks** - tokens clean up automatically when components are destroyed
|
|
356
|
+
- β
**Zero coupling** - no SerializeFields, no GetComponent, no direct references
|
|
357
|
+
- β
**Full visibility** - see message flow in Inspector with timestamps and payloads
|
|
358
|
+
- β
**Predictable order** - priority-based execution (no more mystery race conditions)
|
|
359
|
+
- β
**Type-safe** - compile-time guarantees, refactor with confidence
|
|
360
|
+
- β
**Intercept & validate** - enforce rules before handlers run (clamp damage, block invalid input)
|
|
361
|
+
- β
**Extension points everywhere** - interceptors, handlers, post-processors with priorities
|
|
218
362
|
|
|
219
363
|
## Killer Features
|
|
220
364
|
|
|
221
|
-
|
|
365
|
+
Why DxMessaging is different:
|
|
366
|
+
|
|
367
|
+
### π Performance: Zero-Allocation, Zero-Leak Design
|
|
368
|
+
|
|
369
|
+
**The problem with normal events:** Boxing allocations, GC spikes, memory leaks from forgotten unsubscribes.
|
|
222
370
|
|
|
223
|
-
|
|
371
|
+
#### DxMessaging solution
|
|
224
372
|
|
|
225
373
|
```csharp
|
|
226
|
-
void OnDamage(ref TookDamage msg) { //
|
|
227
|
-
health -= msg.amount;
|
|
374
|
+
void OnDamage(ref TookDamage msg) { // Pass by ref = zero allocations
|
|
375
|
+
health -= msg.amount; // No boxing, no GC pressure
|
|
228
376
|
}
|
|
377
|
+
// Automatic cleanup = zero leaks, guaranteed
|
|
229
378
|
```
|
|
230
379
|
|
|
231
|
-
|
|
380
|
+
**Real-world impact:** A game emitting 1000 messages/second uses **zero GC** with DxMessaging vs. 40KB/sec with boxed events.
|
|
381
|
+
|
|
382
|
+
### π― Three Message Types That Actually Make Sense
|
|
383
|
+
|
|
384
|
+
Most event systems force you into one pattern. DxMessaging gives you the right tool for each job:
|
|
232
385
|
|
|
233
386
|
```csharp
|
|
234
|
-
// Untargeted:
|
|
235
|
-
[DxUntargetedMessage]
|
|
387
|
+
// Untargeted: "Everyone, listen up!" (global announcements)
|
|
388
|
+
[DxUntargetedMessage]
|
|
389
|
+
public struct GamePaused { }
|
|
390
|
+
// β³ Perfect for: settings, scene transitions, global state
|
|
236
391
|
|
|
237
|
-
// Targeted:
|
|
238
|
-
[DxTargetedMessage]
|
|
392
|
+
// Targeted: "Hey Player, do this!" (commands to specific entities)
|
|
393
|
+
[DxTargetedMessage]
|
|
394
|
+
public struct Heal { public int amount; }
|
|
395
|
+
// β³ Perfect for: UI actions, direct commands, player input
|
|
239
396
|
|
|
240
|
-
// Broadcast:
|
|
241
|
-
[DxBroadcastMessage]
|
|
397
|
+
// Broadcast: "I took damage!" (events others can observe)
|
|
398
|
+
[DxBroadcastMessage]
|
|
399
|
+
public struct TookDamage { public int amount; }
|
|
400
|
+
// β³ Perfect for: achievements, analytics, UI updates from entities
|
|
242
401
|
```
|
|
243
402
|
|
|
403
|
+
**Why this matters:** You're not forcing everything through one generic "Event<T>" pattern. Each message type has clear semantics.
|
|
404
|
+
|
|
244
405
|
### π The Message Pipeline
|
|
245
406
|
|
|
246
407
|
Every message flows through 3 stages with priority control:
|
|
@@ -250,51 +411,136 @@ flowchart LR
|
|
|
250
411
|
P[Producer] --> I[Interceptors<br/>validate/mutate]
|
|
251
412
|
I --> H[Handlers<br/>main logic]
|
|
252
413
|
H --> PP[Post-Processors<br/>analytics/logging]
|
|
253
|
-
style I fill:#
|
|
254
|
-
style H fill:#
|
|
255
|
-
style PP fill:#
|
|
414
|
+
style I fill:#ffe7ba,stroke:#d48806,stroke-width:2px,color:#000
|
|
415
|
+
style H fill:#91d5ff,stroke:#096dd9,stroke-width:2px,color:#000
|
|
416
|
+
style PP fill:#b7eb8f,stroke:#389e0d,stroke-width:2px,color:#000
|
|
256
417
|
```
|
|
257
418
|
|
|
258
|
-
### π Listen to
|
|
419
|
+
### π Global Observers: Listen to EVERYTHING (Unique Feature!)
|
|
420
|
+
|
|
421
|
+
**The problem with normal events:** To track all player damage, enemy damage, and NPC damage, you need 3 separate event subscriptions.
|
|
259
422
|
|
|
260
|
-
|
|
423
|
+
**DxMessaging's superpower:** Subscribe ONCE to a message type, receive ALL instances with source information:
|
|
261
424
|
|
|
262
425
|
```csharp
|
|
263
|
-
// Track ALL damage,
|
|
426
|
+
// Track ALL damage from ANY source (players, enemies, NPCs, environment)
|
|
264
427
|
_ = token.RegisterBroadcastWithoutSource<TookDamage>(
|
|
265
428
|
(InstanceId source, TookDamage msg) => {
|
|
429
|
+
Debug.Log($"{source} took {msg.amount} damage!");
|
|
266
430
|
Analytics.LogDamage(source, msg.amount);
|
|
431
|
+
CheckAchievements(source, msg.amount);
|
|
267
432
|
}
|
|
268
433
|
);
|
|
269
434
|
```
|
|
270
435
|
|
|
271
|
-
|
|
436
|
+
#### Real-world use cases
|
|
437
|
+
|
|
438
|
+
- **Achievement system:** Track all kills, deaths, damage across the entire game
|
|
439
|
+
- **Combat log:** "Player took 25 damage, Enemy3 took 50 damage, Boss took 100 damage"
|
|
440
|
+
- **Analytics:** Aggregate stats from all entities without knowing about them upfront
|
|
441
|
+
- **Debug tools:** Watch ALL messages in the Inspector without instrumenting code
|
|
442
|
+
|
|
443
|
+
**Why this is revolutionary:** Traditional event buses require you to know entity types upfront. DxMessaging lets you observe dynamically.
|
|
444
|
+
|
|
445
|
+
### π‘οΈ Interceptors: Validate Before Execution (Safety Built In)
|
|
446
|
+
|
|
447
|
+
**The problem with normal events:** Validation logic duplicated in every handler, or bugs when you forget.
|
|
448
|
+
|
|
449
|
+
**DxMessaging solution:** Validate ONCE before ANY handler runs:
|
|
272
450
|
|
|
273
451
|
```csharp
|
|
274
|
-
//
|
|
452
|
+
// ONE interceptor protects ALL handlers
|
|
275
453
|
_ = token.RegisterBroadcastInterceptor<TookDamage>(
|
|
276
454
|
(ref InstanceId src, ref TookDamage msg) => {
|
|
277
|
-
if (msg.amount <= 0) return false;
|
|
278
|
-
|
|
455
|
+
if (msg.amount <= 0) return false; // Cancel invalid
|
|
456
|
+
if (msg.amount > 999) {
|
|
457
|
+
msg = new TookDamage(999); // Clamp excessive
|
|
458
|
+
}
|
|
459
|
+
if (IsGodModeActive(src)) return false; // Block damage
|
|
279
460
|
return true;
|
|
280
|
-
}
|
|
461
|
+
},
|
|
462
|
+
priority: -100 // Run FIRST
|
|
281
463
|
);
|
|
464
|
+
|
|
465
|
+
// Now ALL handlers receive clean, validated data
|
|
466
|
+
_ = token.RegisterComponentTargeted<TookDamage>(player, OnDamage);
|
|
467
|
+
void OnDamage(ref TookDamage msg) {
|
|
468
|
+
// No validation needed - interceptor guarantees validity!
|
|
469
|
+
health -= msg.amount;
|
|
470
|
+
}
|
|
282
471
|
```
|
|
283
472
|
|
|
284
|
-
|
|
473
|
+
#### Real-world use cases
|
|
474
|
+
|
|
475
|
+
- Clamp/normalize values (damage, healing, speeds)
|
|
476
|
+
- Enforce game rules ("can't heal above max health")
|
|
477
|
+
- Block messages during cutscenes
|
|
478
|
+
- Log/audit sensitive actions
|
|
479
|
+
|
|
480
|
+
### π Built-in Inspector Diagnostics (Actually Debuggable!)
|
|
481
|
+
|
|
482
|
+
**The problem with normal events:** "Which event fired? When? Who handled it? In what order?" = π€·
|
|
483
|
+
|
|
484
|
+
**DxMessaging solution:** Click any `MessageAwareComponent` in the Inspector:
|
|
485
|
+
|
|
486
|
+
#### Message History (last 50)
|
|
285
487
|
|
|
286
|
-
|
|
488
|
+
- `[12:34:56.123] HealthChanged`
|
|
489
|
+
- amount: 25
|
|
490
|
+
- priority: 0
|
|
491
|
+
- handlers: 3
|
|
492
|
+
- `[12:34:55.987] ItemAdded`
|
|
493
|
+
- itemId: 42, count: 1
|
|
494
|
+
- priority: 5
|
|
495
|
+
- handlers: 2
|
|
287
496
|
|
|
288
|
-
|
|
497
|
+
##### Active Registrations
|
|
289
498
|
|
|
290
|
-
|
|
499
|
+
- β HealthChanged (priority: 0, called: 847 times)
|
|
500
|
+
- β ItemAdded (priority: 5, called: 23 times)
|
|
501
|
+
- β TookDamage (priority: 10, called: 1,203 times)
|
|
502
|
+
|
|
503
|
+
#### Real-world debugging scenarios
|
|
504
|
+
|
|
505
|
+
- "Did my message fire?" β Check history, see timestamp
|
|
506
|
+
- "Why didn't my handler run?" β Check registrations, see if it's active
|
|
507
|
+
- "What's firing too often?" β Sort by call count
|
|
508
|
+
- "What's the execution order?" β Sort by priority
|
|
509
|
+
|
|
510
|
+
**No more:** Setting 50 breakpoints and stepping through code for 30 minutes.
|
|
511
|
+
|
|
512
|
+
### ποΈ Local Bus Islands for Testing (Actually Testable!)
|
|
513
|
+
|
|
514
|
+
**The problem with normal events:** Global static events contaminate tests. Mock hell. Flaky tests.
|
|
515
|
+
|
|
516
|
+
**DxMessaging solution:** Each test gets its own isolated message bus:
|
|
291
517
|
|
|
292
518
|
```csharp
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
//
|
|
519
|
+
[Test]
|
|
520
|
+
public void TestAchievementSystem() {
|
|
521
|
+
// Create isolated bus - zero global state
|
|
522
|
+
var testBus = new MessageBus();
|
|
523
|
+
var handler = new MessageHandler(new InstanceId(1), testBus) { active = true };
|
|
524
|
+
var token = MessageRegistrationToken.Create(handler, testBus);
|
|
525
|
+
|
|
526
|
+
// Test in isolation
|
|
527
|
+
_ = token.RegisterBroadcastWithoutSource<EnemyKilled>(achievements.OnKill);
|
|
528
|
+
|
|
529
|
+
var msg = new EnemyKilled("Boss");
|
|
530
|
+
msg.EmitGameObjectBroadcast(enemy, testBus); // Only this test sees it
|
|
531
|
+
|
|
532
|
+
Assert.IsTrue(achievements.Unlocked("BossSlayer"));
|
|
533
|
+
}
|
|
534
|
+
// Bus destroyed, zero cleanup needed
|
|
296
535
|
```
|
|
297
536
|
|
|
537
|
+
#### Why this matters
|
|
538
|
+
|
|
539
|
+
- Tests don't interfere with each other
|
|
540
|
+
- No "arrange/act/cleanup" boilerplate
|
|
541
|
+
- No mocking frameworks needed
|
|
542
|
+
- Parallel test execution works perfectly
|
|
543
|
+
|
|
298
544
|
## Documentation
|
|
299
545
|
|
|
300
546
|
### π Learn
|
|
@@ -325,9 +571,64 @@ Important: Inheritance with MessageAwareComponent
|
|
|
325
571
|
- If you need to opt out of string demos, override `RegisterForStringMessages => false` instead of skipping the base call.
|
|
326
572
|
- Donβt hide Unity methods with `new` (e.g., `new void OnEnable()`); always `override` and call `base.*`.
|
|
327
573
|
|
|
574
|
+
### π§© DI Framework Integrations
|
|
575
|
+
|
|
576
|
+
DxMessaging works standalone (zero dependencies) or with any major DI framework. For detailed setup guides and code examples:
|
|
577
|
+
|
|
578
|
+
- **[Zenject Integration Guide](Docs/Integrations/Zenject.md)** β Full-featured DI with extensive Unity support
|
|
579
|
+
- **[VContainer Integration Guide](Docs/Integrations/VContainer.md)** β Lightweight DI with scoped lifetimes for scene isolation
|
|
580
|
+
- **[Reflex Integration Guide](Docs/Integrations/Reflex.md)** β Minimal API, blazing-fast performance
|
|
581
|
+
|
|
582
|
+
#### Core DI concepts
|
|
583
|
+
|
|
584
|
+
- **[Runtime Configuration](Docs/RuntimeConfiguration.md)** β Setting and overriding message buses at runtime, re-binding registrations
|
|
585
|
+
- **[Message Bus Providers](Docs/MessageBusProviders.md)** β Provider system and MessageBusProviderHandle for flexible bus configuration
|
|
586
|
+
|
|
587
|
+
Each guide includes:
|
|
588
|
+
|
|
589
|
+
- β
Complete setup instructions with installers
|
|
590
|
+
- β
Multiple usage patterns (plain classes, MonoBehaviours, direct injection)
|
|
591
|
+
- β
Testing examples with isolated buses
|
|
592
|
+
- β
Advanced patterns (pooling, scene scopes, signal bridges)
|
|
593
|
+
|
|
594
|
+
See the [π§ DI Compatible section](#-dependency-injection-di-compatible) above for a quick overview.
|
|
595
|
+
|
|
328
596
|
### π Comparisons
|
|
329
597
|
|
|
330
|
-
- [Compare with C# events, UnityEvents, and
|
|
598
|
+
- [Compare with Other Unity Messaging Frameworks](Docs/Comparisons.md) β In-depth comparison with UniRx, MessagePipe, Zenject Signals, C# events, UnityEvents, and more
|
|
599
|
+
- [Scriptable Object Architecture (SOA) Compatibility](Docs/Patterns.md#14-compatibility-with-scriptable-object-architecture-soa) β Migration patterns and interoperability with SOA
|
|
600
|
+
|
|
601
|
+
#### Quick Framework Comparison
|
|
602
|
+
|
|
603
|
+
| Framework | Best For | Key Strength | Unity Support | Learning Curve |
|
|
604
|
+
| ------------------- | --------------------------------- | -------------------------------- | ------------------ | -------------- |
|
|
605
|
+
| **DxMessaging** | Unity pub/sub with lifecycle mgmt | Inspector debugging + control | β
Built for Unity | βββ |
|
|
606
|
+
| **UniRx** | Complex event stream transforms | Reactive operators (LINQ) | β
Built for Unity | ββ |
|
|
607
|
+
| **MessagePipe** | High-performance DI messaging | Highest throughput (97M ops/sec) | β
Built for Unity | ββββ |
|
|
608
|
+
| **Zenject Signals** | DI-integrated messaging | Zenject ecosystem | β
Built for Unity | ββ |
|
|
609
|
+
| **C# Events** | Simple, local communication | Minimal overhead | β
Native C# | βββββ |
|
|
610
|
+
|
|
611
|
+
##### Choose DxMessaging when you want
|
|
612
|
+
|
|
613
|
+
- Unity-first design with GameObject/Component targeting
|
|
614
|
+
- Automatic lifecycle management (zero memory leaks)
|
|
615
|
+
- Inspector debugging to see message flow and history
|
|
616
|
+
- Execution order control (priority-based handlers)
|
|
617
|
+
- Message validation/interception pipeline
|
|
618
|
+
- Global observers (listen to all message instances)
|
|
619
|
+
- Post-processing stage (analytics, logging after handlers)
|
|
620
|
+
- No dependencies, plug-and-play setup
|
|
621
|
+
|
|
622
|
+
See [full comparison](Docs/Comparisons.md) for detailed analysis with code examples, performance benchmarks, and decision guides.
|
|
623
|
+
|
|
624
|
+
> **π¦ Using Scriptable Object Architecture (SOA)?**
|
|
625
|
+
>
|
|
626
|
+
> DxMessaging can work alongside or replace SOA patterns. See [SOA Compatibility Guide](Docs/Patterns.md#14-compatibility-with-scriptable-object-architecture-soa) for:
|
|
627
|
+
>
|
|
628
|
+
> - Fair comparison of SOA vs. DxMessaging
|
|
629
|
+
> - Migration patterns from GameEvent/FloatVariable to DxMessaging
|
|
630
|
+
> - How to use both systems together (SOs for configs, DxMessaging for events)
|
|
631
|
+
> - When to keep using ScriptableObjects (immutable design data)
|
|
331
632
|
|
|
332
633
|
### π Reference
|
|
333
634
|
|
|
@@ -400,6 +701,26 @@ For OS-specific benchmark tables generated by PlayMode tests, see [Performance B
|
|
|
400
701
|
|
|
401
702
|
## Comparison Table
|
|
402
703
|
|
|
704
|
+
### Comparison with Unity Messaging Frameworks
|
|
705
|
+
|
|
706
|
+
| Feature | DxMessaging | UniRx | MessagePipe | Zenject Signals |
|
|
707
|
+
| ------------------------ | ------------------ | ------------------ | ------------------ | ------------------ |
|
|
708
|
+
| **Unity Compatibility** | β
Built for Unity | β
Built for Unity | β
Built for Unity | β
Built for Unity |
|
|
709
|
+
| **Decoupling** | β
Full | β
Full | β
Full | β
Full |
|
|
710
|
+
| **Lifecycle Safety** | β
Auto | β οΈ Manual | β οΈ Manual | β οΈ DI-managed |
|
|
711
|
+
| **Execution Order** | β
Priority | β None | β None | β None |
|
|
712
|
+
| **Type Safety** | β
Strong | β
Strong | β
Strong | β
Strong |
|
|
713
|
+
| **Inspector Debug** | β
Built-in | β No | β No | β No |
|
|
714
|
+
| **GameObject Targeting** | β
Yes | β No | β No | β No |
|
|
715
|
+
| **Global Observers** | β
Yes | β No | β No | β No |
|
|
716
|
+
| **Interceptors** | β
Pipeline | β No | β οΈ Filters | β No |
|
|
717
|
+
| **Post-Processing** | β
Dedicated | β No | β οΈ Filters | β No |
|
|
718
|
+
| **Stream Operators** | β No | β
Extensive | β No | β οΈ With UniRx |
|
|
719
|
+
| **Performance** | β
Good (14M) | β
Good (18M) | β
Best (97M) | β οΈ Moderate (2.5M) |
|
|
720
|
+
| **Dependencies** | β
None | β οΈ UniTask | β
None | β οΈ Zenject |
|
|
721
|
+
|
|
722
|
+
### Comparison with Traditional Approaches
|
|
723
|
+
|
|
403
724
|
| Feature | DxMessaging | C# Events | UnityEvents | Static Event Bus |
|
|
404
725
|
| ---------------------- | ------------- | ------------ | ------------- | ---------------- |
|
|
405
726
|
| **Decoupling** | β
Full | β Tight | β οΈ Hidden | β
Yes |
|
package/Runtime/AssemblyInfo.cs
CHANGED
|
@@ -5,3 +5,7 @@ using System.Runtime.CompilerServices;
|
|
|
5
5
|
AllInternalsVisible = true
|
|
6
6
|
)]
|
|
7
7
|
[assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Editor")]
|
|
8
|
+
[assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime")]
|
|
9
|
+
[assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.Reflex")]
|
|
10
|
+
[assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.VContainer")]
|
|
11
|
+
[assembly: InternalsVisibleTo("WallstopStudios.DxMessaging.Tests.Runtime.Zenject")]
|